Skip to content

Add resource collector pipeline; migrate population growth and country score#33

Merged
KonH merged 4 commits into
mainfrom
claude/resource-collector-pipeline-qehxfi
Jul 20, 2026
Merged

Add resource collector pipeline; migrate population growth and country score#33
KonH merged 4 commits into
mainfrom
claude/resource-collector-pipeline-qehxfi

Conversation

@KonH

@KonH KonH commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Introduces IResourceCollector/ResourceCollectorRegistry/ResourceCollector,
mirroring the BotFeatureRegistry pattern, so a ResourceEffect's Value can be
recomputed from world state each time it is processed instead of staying
static. ResourceSystem.Update gains optional collectorRegistry/
resourceIdUpdateOrder parameters that resolve-then-apply effects resourceId
by resourceId in a configured order, so a later resourceId's collector can
read an earlier one's already-applied value within the same tick. Existing
call sites are unaffected (null/empty args reproduce the old single-pass
behavior exactly).

Migrates three mechanics onto the new pipeline:

  • Province population growth becomes a self-referential Monthly collector
    effect; ProvincePopulationGrowthSystem is removed.
  • New country_population resource, fed by a collector that sums the
    population of every province currently owned by that country.
  • country_score moves from a Score component composed onto Country to a
    Resource fed by a collector reading country_population * coefficient.
    CountryScoreSystem.GetScore is preserved as a query over the new storage.
    OrgScoreSystem.Recompute and VisualStateConverter.UpdateCountryScore are
    updated to read scores via GetScore instead of a Country+Score archetype.

InitSystem.Run gains a bootstrap resolve-then-apply pass (previousTime ==
currentTime, so only Instant effects fire) so country_population/
country_score seed correctly before OrgScoreSystem.Recompute reads them,
without disturbing province population's Monthly-only growth on the first
tick.

Adds resourceIdUpdateOrder to GameSettings/game_settings.json (default:
population, country_population, country_score) and updates
ecs_patterns.md's composition example to reflect the move.

Note: Assets/Plugins/Core/*.dll are not rebuilt in this commit — the .NET
SDK is unavailable in this sandbox (network egress to the dotnet CDN is
blocked, and apt's dotnet packages 404). dotnet build
src/GlobalStrategy.Core.sln -c Release and dotnet test
src/GlobalStrategy.Core.sln still need to be run in an environment with the
SDK before this is considered verified.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01GLxj7CXoSVmUHzKZe6PSxa

claude and others added 4 commits July 18, 2026 18:11
…y score

Introduces IResourceCollector/ResourceCollectorRegistry/ResourceCollector,
mirroring the BotFeatureRegistry pattern, so a ResourceEffect's Value can be
recomputed from world state each time it is processed instead of staying
static. ResourceSystem.Update gains optional collectorRegistry/
resourceIdUpdateOrder parameters that resolve-then-apply effects resourceId
by resourceId in a configured order, so a later resourceId's collector can
read an earlier one's already-applied value within the same tick. Existing
call sites are unaffected (null/empty args reproduce the old single-pass
behavior exactly).

Migrates three mechanics onto the new pipeline:
- Province population growth becomes a self-referential Monthly collector
  effect; ProvincePopulationGrowthSystem is removed.
- New country_population resource, fed by a collector that sums the
  population of every province currently owned by that country.
- country_score moves from a Score component composed onto Country to a
  Resource fed by a collector reading country_population * coefficient.
  CountryScoreSystem.GetScore is preserved as a query over the new storage.
  OrgScoreSystem.Recompute and VisualStateConverter.UpdateCountryScore are
  updated to read scores via GetScore instead of a Country+Score archetype.

InitSystem.Run gains a bootstrap resolve-then-apply pass (previousTime ==
currentTime, so only Instant effects fire) so country_population/
country_score seed correctly before OrgScoreSystem.Recompute reads them,
without disturbing province population's Monthly-only growth on the first
tick.

Adds resourceIdUpdateOrder to GameSettings/game_settings.json (default:
population, country_population, country_score) and updates
ecs_patterns.md's composition example to reflect the move.

Note: Assets/Plugins/Core/*.dll are not rebuilt in this commit — the .NET
SDK is unavailable in this sandbox (network egress to the dotnet CDN is
blocked, and apt's dotnet packages 404). dotnet build
src/GlobalStrategy.Core.sln -c Release and dotnet test
src/GlobalStrategy.Core.sln still need to be run in an environment with the
SDK before this is considered verified.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GLxj7CXoSVmUHzKZe6PSxa
- Fix stale Score.cs comment still describing the removed
  CountryScoreSystem.Update/Recompute-driven Country+Score composition.
- Document the silent-no-op risk when a ResourceCollector-tagged effect's
  resourceId isn't listed in resourceIdUpdateOrder.
- Add CountryScoreCollector.ResourceId ("country_score") as the shared
  constant, matching the pattern already used for "population"/
  "country_population", and reference it from InitSystem.cs,
  CountryScoreSystem.GetScore, and OrgScoreSystemTests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GLxj7CXoSVmUHzKZe6PSxa
Adds a fourth resourceId, recruits, on top of the resource collector
pipeline: seeds at recruitsInitialPercent% of country_population via an
Instant collector effect, grows monthly by recruitsMonthlyIncreasePercent%
of the current country_population via a Monthly collector effect, clamped
to recruitsCapPercent% of country_population (never negative, so recruits
never shrinks when population — and its cap — drops). No new mechanism:
two IResourceCollector implementations (RecruitsSeedCollector,
RecruitsGrowthCollector) plugged into the existing pipeline, and recruits
is appended to resourceIdUpdateOrder after country_population so both
collectors always read that pass's already-aggregated total.

Extracts src/Game.Systems/ResourceQuery.cs (GetValue(world, ownerId,
resourceId)) as the single shared "look up a country-owned resource by id"
implementation, and refactors CountryScoreCollector.Compute,
CountryScoreSystem.GetScore, and ResourceSystem's internal collector-resolve
lookup to all go through it instead of three near-identical inline scans.

ResourceCollectorRegistry.CreateDefault gains three new parameters
(recruitsInitialPercent, recruitsCapPercent, recruitsMonthlyIncreasePercent);
both call sites (GameLogic's constructor and InitSystem.Run's bootstrap
resolve pass) are updated. Three new GameSettings/game_settings.json
tunables added (defaults: 5/15/1). No VisualState/VisualStateConverter
change — recruits' total and last-applied-delta already surface through the
existing generic Resource/ResourceEffect display path the same way gold
does.

Note: Assets/Plugins/Core/*.dll are not rebuilt in this commit — the .NET
SDK is unavailable in this sandbox (network egress to the dotnet CDN is
blocked, and apt's dotnet packages 404). dotnet build
src/GlobalStrategy.Core.sln -c Release and dotnet test
src/GlobalStrategy.Core.sln still need to be run in an environment with the
SDK before this is considered verified.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GLxj7CXoSVmUHzKZe6PSxa
Eliminates the Score component and its OrgScoreSystem/CountryScoreSystem
wrappers now that both country and org scores run through the same
generic Resource/ResourceEffect/ResourceCollector pipeline as
population/recruits, adding PayType.Daily so org_score can recompute on
day boundaries where control changes land.

Also tightens InitSystem to stop calling other systems directly
(ProvinceOwnershipSystem.Seed, ResourceSystem.Update) - those now run
from GameLogic's regular per-tick pipeline, self-gated by the existing
IsInitialized marker or by Instant effects self-destroying after their
first apply, per the new "no system-to-system calls" ECS rule.

Consolidates every resource id string (gold/population/country_score/
org_score/recruits/etc.) that was previously duplicated across collector
classes and call sites into a single ResourceDefinitions class in
Game.Configs, the one project every consumer already depends on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@KonH
KonH merged commit d4918be into main Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants