sots-engine/CMakeLists.txt
alex 0ebc222f45 lane N: the population -> base-output term, live-verified
Reads the whole colony output chain off the instruction stream (every range
disassembled to the next function start) and compares two of its functions
against the running game.

The population -> output law is linear and is carried by the executable:
output points per head are typeOutputModifier x 1.8 / 500000, and the
three-row population-type table is built in code rather than loaded, so the
imperial (1.0) and civilian (0.33f) modifiers are facts about the binary.

A system's total output is a SUM of three terms, not one multiplicative
chain. The station bonus scales only the imperial term and morale only the
civilian one, so OutputModifiers no longer carries either; they belong to
GroupOutputInputs. The function previously described as the base-output term
is the over-harvest RESOURCE demand, and it is corrected in place.

Live on VM140, both hooks in compare mode over two species and two workloads:
GroupOutput 13,105 calls / 0 divergences; ComputeTotalOutput 11,252 calls /
1 divergence of one ulp, in a value its caller rounds to an integer. Both
functions declare a whole-object Guard: 0 undeclared writes in 24,357 calls,
which is what makes the side-effect-free claim a measurement.

sim::Narrow forces the double rounding a 32-bit x87 build otherwise skips;
without it every civilian row came out one ulp low.

Also fixes ComputeBankruptcyLimits' elimination divisor, which was the
decimal -0.15 rather than the image's widened float -0.15000000596046448.
The two disagree for every maximum income divisible by 3 and for essentially
every empire above ~3,000,000.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARBgSooAfokKUy6wKUKEyZ
2026-09-08 12:11:36 -04:00

128 lines
7.4 KiB
CMake

cmake_minimum_required(VERSION 3.25)
project(sots-engine LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Build id stamped into the shim log banner (tools/build-shim.sh passes git describe + UTC time).
set(SHIM_BUILD_ID "dev" CACHE STRING "Build identifier logged by the shim")
# Provenance of the binary facts: the generated header's own "Source:" line, forwarded verbatim
# so every shim.log records which RE snapshot the RVAs came from.
file(STRINGS include/generated/sots_addresses.h _addr_provenance REGEX "^// Source:")
list(GET _addr_provenance 0 _addr_provenance)
string(REGEX REPLACE "^// " "" SOTS_ADDR_PROVENANCE "${_addr_provenance}")
add_library(sots_addresses INTERFACE)
target_include_directories(sots_addresses INTERFACE ${CMAKE_SOURCE_DIR}/include)
# ---- engine modules (host + cross): pure, oracle-verified code accrues here ----
add_subdirectory(src/mars/parse) # brace-block + .effect readers (lib mars_parse)
add_subdirectory(src/mars/text) # flat-kv, id-manifest, csv (lib mars_text)
add_subdirectory(src/game/sim) # strategic formulas, pure (lib sots_game_sim)
add_subdirectory(src/mars/vfs) # .gob ZIP reader + native override (lib mars_vfs, miniz)
add_subdirectory(src/mars/stream) # Streamable save format + gzip (lib mars_stream)
add_subdirectory(src/mars/rng) # MT19937 (lib mars_rng)
add_subdirectory(src/game/config) # flat KEY/value constants loader (lib sots_game_config)
add_subdirectory(src/game/data) # typed catalogs on mars/parse+text (lib game_data)
add_subdirectory(src/game/effects) # tech effects (TechId table + apply) (lib game_effects)
add_subdirectory(src/game/design) # ship-design rules + derived stats (lib game_design)
add_subdirectory(src/game/events) # player event log + research events (lib sots_game_events)
add_subdirectory(src/game/combat) # post-battle strategic consequences (lib sots_game_combat)
add_subdirectory(src/app) # the standalone turn driver (lib sots_app, sots_turn)
# ---- shim trace/compare infrastructure (host-testable; linked into binkw32) ----
add_library(shim_trace STATIC
src/shim/trace/sha256.cpp
src/shim/trace/emitter.cpp
src/shim/trace/tracer.cpp
src/shim/trace/selftest.cpp)
target_include_directories(shim_trace PUBLIC ${CMAKE_SOURCE_DIR}/src)
target_compile_options(shim_trace PRIVATE -Wall -Wextra -Werror)
if(MINGW)
target_compile_definitions(shim_trace PUBLIC __USE_MINGW_ANSI_STDIO=1) # C99 %lld/%.17g
endif()
# ---- B1 budget adapter: ServerPlayer snapshot <-> game::sim economy (pure, host-tested) ----
add_library(shim_budget STATIC src/shim/hooks/budget_inputs.cpp)
target_link_libraries(shim_budget PUBLIC shim_trace sots_game_sim)
target_compile_options(shim_budget PRIVATE -Wall -Wextra -Werror)
# ---- B2 tech-effect adapter: ServerPlayer fields <-> game::effects state (pure, host-tested) ----
add_library(shim_techfx STATIC src/shim/hooks/tech_effect_fields.cpp)
target_link_libraries(shim_techfx PUBLIC shim_trace sots_addresses sots_game_effects)
target_compile_options(shim_techfx PRIVATE -Wall -Wextra -Werror)
# ---- B4 colony adapter: ServerSystem snapshot <-> game::sim colony turn (pure, host-tested) ----
add_library(shim_colony STATIC src/shim/hooks/colony_inputs.cpp)
target_link_libraries(shim_colony PUBLIC shim_trace sots_game_sim)
target_compile_options(shim_colony PRIVATE -Wall -Wextra -Werror)
# ---- B4 movement adapter: StarFleet snapshot <-> game::sim movement (pure, host-tested) ----
add_library(shim_movement STATIC src/shim/hooks/movement_inputs.cpp)
target_link_libraries(shim_movement PUBLIC shim_trace sots_game_sim)
target_compile_options(shim_movement PRIVATE -Wall -Wextra -Werror)
# ---- T turn-driver adapter: ServerPlayer snapshot <-> the driver's own writes (pure, host-tested) ----
add_library(shim_player_turn STATIC src/shim/hooks/player_turn_inputs.cpp)
target_link_libraries(shim_player_turn PUBLIC shim_trace)
target_compile_options(shim_player_turn PRIVATE -Wall -Wextra -Werror)
# ---- P events adapter: live Game::EventStorage <-> sots::events model (pure, host-tested) ----
add_library(shim_events STATIC src/shim/hooks/event_inputs.cpp)
target_link_libraries(shim_events PUBLIC shim_trace sots_addresses sots_game_events)
target_compile_options(shim_events PRIVATE -Wall -Wextra -Werror)
# ---- shim: the strategic RNG word ledger (lane Z) -- absolute generator position recovered
# from (mt[624], left) alone, so a turn's RNG cost can be attributed to a phase without
# hooking a single RNG primitive. Host-testable; linked into the hook descriptors below.
add_library(shim_rng_ledger STATIC src/shim/hooks/rng_ledger.cpp)
target_link_libraries(shim_rng_ledger PUBLIC shim_trace sots_addresses mars_rng)
target_compile_options(shim_rng_ledger PRIVATE -Wall -Wextra -Werror)
if(WIN32)
# ---- shim: proxy binkw32.dll that the original game loads (Phase 2 frontend) ----
add_library(minhook STATIC
third_party/minhook/src/buffer.c
third_party/minhook/src/hook.c
third_party/minhook/src/trampoline.c
third_party/minhook/src/hde/hde32.c)
target_include_directories(minhook PUBLIC third_party/minhook/include)
# ---- hooks: one descriptor per hooked game function (src/shim/hooks/*) ----
add_library(shim_hooks STATIC src/shim/hooks/global_consts.cpp src/shim/hooks/dictionaries.cpp
src/shim/hooks/research.cpp
src/shim/hooks/tech_effects.cpp
src/shim/hooks/compute_budget.cpp
src/shim/hooks/colony_turn.cpp
src/shim/hooks/system_output.cpp
src/shim/hooks/fleet_movement.cpp
src/shim/hooks/player_turn.cpp
src/shim/hooks/tail_rng.cpp
src/shim/hooks/draw_sites.cpp)
target_link_libraries(shim_hooks PUBLIC shim_trace sots_addresses sots_game_config sots_game_sim
sots_game_effects mars_rng shim_budget shim_techfx
shim_colony shim_movement shim_events
shim_player_turn shim_rng_ledger)
target_compile_options(shim_hooks PRIVATE -Wall -Wextra -Werror)
add_library(binkw32 SHARED src/shim/main.cpp src/shim/fpu_force.cpp src/shim/binkw32.def)
target_link_libraries(binkw32 PRIVATE minhook sots_addresses shim_trace shim_hooks)
target_compile_definitions(binkw32 PRIVATE
SHIM_BUILD_ID="${SHIM_BUILD_ID}"
SOTS_ADDR_PROVENANCE="${SOTS_ADDR_PROVENANCE}")
# Must be exactly binkw32.dll (no "lib" prefix); export names come solely from the .def.
set_target_properties(binkw32 PROPERTIES PREFIX "" OUTPUT_NAME "binkw32")
else()
# ---- host: engine module tests (ctest) + a header smoke test ----
enable_testing()
add_executable(addr_smoke tests/addr_smoke.cpp)
target_link_libraries(addr_smoke PRIVATE sots_addresses)
add_test(NAME addr_smoke COMMAND addr_smoke)
foreach(_t mars_parse game_config game_data game_design game_sim mars_stream mars_text mars_vfs shim_trace game_effects game_events game_combat shim_budget shim_techfx shim_colony shim_movement shim_events shim_player_turn shim_rng_ledger app)
if(EXISTS ${CMAKE_SOURCE_DIR}/tests/${_t}/CMakeLists.txt)
add_subdirectory(tests/${_t})
endif()
endforeach()
endif()