shim: research.replace_cascade, and a completion counter that prints in replace mode too
The B3 hook's unlock cascade was compare-mode only, so a replace run left the completed node unstamped and no tech unlocked -- and its only per-call counter was gated on the cascade, so a replace run had no instrument of its own saying a completion had happened at all. Lane CR needs both halves to ask whether ProcessResearch can be displaced. research.replace_cascade=on (default off, so the shipped behaviour is unchanged and still measurable) lets a replace-mode call write the four TechNode words SetResearched stamps and the tree's completion-order counter. The ServerPlayer half of the callback stays unmodelled and stays declared: no event is posted, no ObservedTech element is appended, no tech effect is applied. The pair of settings is the measurement -- same binary, one config line, and the leaf difference between the two autosaves is the cascade's own contribution. The per-call log line now prints in every mode and counts completions from the pass's own step results, so 'a completion fired' is a statement by the instrument rather than an inference from the artefact under test.
This commit is contained in:
parent
e7e2bd6f62
commit
618ccb1c25
7 changed files with 203 additions and 24 deletions
|
|
@ -79,6 +79,11 @@ struct Env {
|
||||||
std::uintptr_t exe_base = 0;
|
std::uintptr_t exe_base = 0;
|
||||||
void (*log_line)(const char*) = nullptr;
|
void (*log_line)(const char*) = nullptr;
|
||||||
CostFn cost = nullptr;
|
CostFn cost = nullptr;
|
||||||
|
// `research.replace_cascade=on` (lane CR). Default OFF, so a build behaves exactly as it
|
||||||
|
// did before this key existed and the two replace configurations differ by configuration
|
||||||
|
// rather than by binary. See ours() for what the flag does and, just as important, what it
|
||||||
|
// deliberately still does not do.
|
||||||
|
bool replace_cascade = false;
|
||||||
};
|
};
|
||||||
Env g_env;
|
Env g_env;
|
||||||
|
|
||||||
|
|
@ -934,17 +939,29 @@ void TechTreeProcessResearchHook::ours(void* tree, void* rng, void* alloc, int*
|
||||||
// completed node's turn/order stamps, the child costs and states, the availability stamp
|
// completed node's turn/order stamps, the child costs and states, the availability stamp
|
||||||
// EVENT_TECHS_UNLOCKED is computed from, the observed-tech append, and one RNG word.
|
// EVENT_TECHS_UNLOCKED is computed from, the observed-tech append, and one RNG word.
|
||||||
//
|
//
|
||||||
// It runs in COMPARE MODE ONLY, for the same reason the event post does. In replace mode
|
// It ran in COMPARE MODE ONLY until lane CR, for the same reason the event post still does:
|
||||||
// every pointer here is live game memory, and running half of OnTechResearched -- the
|
// in replace mode every pointer here is live game memory, and running half of
|
||||||
// observed-tech append and the research-event roll, but not the ninety-odd tech-effect field
|
// OnTechResearched -- the observed-tech append and the research-event roll, but not the
|
||||||
// writes -- would leave the player in a state no code path produces. Not running it leaves a
|
// ninety-odd tech-effect field writes -- leaves the player in a state no code path produces.
|
||||||
// player missing a cascade, which is a smaller and already-declared lie.
|
|
||||||
//
|
//
|
||||||
// The graph is transcribed from the SCRATCH node copies, so what the cascade decides is a
|
// `research.replace_cascade=on` opts a replace run into the half that is entirely inside this
|
||||||
// function of the pre-call tree and not of what the original just did to the live one.
|
// subsystem: the four TechNode words SetResearched stamps (costRP, turnAvailable,
|
||||||
|
// turnResearched, order) and the tree's own completion-order counter. Those are TechTree
|
||||||
|
// state, they are what the compare has been checking for a day, and writing them live is what
|
||||||
|
// SetResearched does. Everything the callback does to the *player* stays unmodelled and stays
|
||||||
|
// declared -- the event post, the ObservedTech element and the tech-effect fields -- so a
|
||||||
|
// replace run with the flag on is still a partial displacement, by exactly the boundary the
|
||||||
|
// coverage notes name. The point of the flag is to make that boundary measurable: the same
|
||||||
|
// binary, the same save, two configurations, and the leaf difference between their autosaves
|
||||||
|
// is the cascade's own contribution.
|
||||||
|
//
|
||||||
|
// The graph is transcribed from the node copies -- SCRATCH in compare mode, the live nodes in
|
||||||
|
// replace mode, where nothing has run yet -- so in both cases what the cascade decides is a
|
||||||
|
// function of the pre-call tree and not of what the original just did.
|
||||||
sots::sim::TechGraph graph;
|
sots::sim::TechGraph graph;
|
||||||
CascadeCtx cc;
|
CascadeCtx cc;
|
||||||
const bool cascade_possible = compare && g_scan.turn_ok && g_pre.tree_ok;
|
const bool cascade_possible =
|
||||||
|
(compare || g_env.replace_cascade) && g_scan.turn_ok && g_pre.tree_ok;
|
||||||
bool cascade_ok = false;
|
bool cascade_ok = false;
|
||||||
if (cascade_possible) {
|
if (cascade_possible) {
|
||||||
cascade_ok = build_graph(nodes, graph);
|
cascade_ok = build_graph(nodes, graph);
|
||||||
|
|
@ -989,6 +1006,14 @@ void TechTreeProcessResearchHook::ours(void* tree, void* rng, void* alloc, int*
|
||||||
set_word(p, A::TechNode_off_TurnResearched, graph.nodes[i].turnResearched);
|
set_word(p, A::TechNode_off_TurnResearched, graph.nodes[i].turnResearched);
|
||||||
set_word(p, A::TechNode_off_Order, graph.nodes[i].order);
|
set_word(p, A::TechNode_off_Order, graph.nodes[i].order);
|
||||||
}
|
}
|
||||||
|
// The counter the `order` stamps came from. In compare mode `tree` is the LIVE tree (only
|
||||||
|
// the nodes are copied), so this must never run there -- writing it would move a byte the
|
||||||
|
// tree_header guard is there to watch, on a run whose whole value is that ours touched
|
||||||
|
// nothing. In replace mode nothing else advances it, and leaving it behind would make the
|
||||||
|
// next completion reuse an order number.
|
||||||
|
if (!compare && g_pre.tree_ok) {
|
||||||
|
set_word(tree, A::TechTree_off_OrderCounter, graph.orderCounter);
|
||||||
|
}
|
||||||
cc.unlocked = sots::sim::CollectNewlyAvailable(graph, g_scan.turn);
|
cc.unlocked = sots::sim::CollectNewlyAvailable(graph, g_scan.turn);
|
||||||
}
|
}
|
||||||
set_word(overbudget, 0, word_at(overbudget, 0) + r.overbudget);
|
set_word(overbudget, 0, word_at(overbudget, 0) + r.overbudget);
|
||||||
|
|
@ -1094,22 +1119,49 @@ void TechTreeProcessResearchHook::ours(void* tree, void* rng, void* alloc, int*
|
||||||
// A line per call, so a run can be read without the trace: these are the counts that say the
|
// A line per call, so a run can be read without the trace: these are the counts that say the
|
||||||
// cascade actually ran, and a clean compare with all of them at zero would be a clean compare
|
// cascade actually ran, and a clean compare with all of them at zero would be a clean compare
|
||||||
// of nothing.
|
// of nothing.
|
||||||
if (cascade_possible) {
|
//
|
||||||
logf("research: cascade ok=%d completions=%d unlocked=%u otch_appends=%d roll_draws=%d "
|
// `steps`/`completed` are counted from the PASS itself and are therefore printed in every
|
||||||
"failures=%d depth=%d name_unreadable=%d",
|
// mode, cascade or no cascade. That is the point: rule 1 says a green verdict on a hook that
|
||||||
cascade_ok ? 1 : 0, cc.completions, static_cast<unsigned>(cc.unlocked.size()),
|
// may be comparing nothing is not evidence, and the same holds for a green replace-mode
|
||||||
cc.observed_appends, cc.roll_draws, cc.cascade_failures, cc.depth_exceeded ? 1 : 0,
|
// ORACLE. Without this line a replace run with the cascade off has no counter at all -- the
|
||||||
cc.name_unreadable ? 1 : 0);
|
// old log line was gated on the cascade -- so "a completion happened" could only ever be
|
||||||
|
// inferred from the save, which is the artefact under test. Counted here, it is a statement
|
||||||
|
// by the instrument about what our own code did.
|
||||||
|
int model_completions = 0;
|
||||||
|
for (const sots::sim::ResearchStepResult& s : r.steps)
|
||||||
|
if (s.completed) ++model_completions;
|
||||||
|
logf("research: mode=%s steps=%u completions=%d overbudget=%d cascade_possible=%d ok=%d "
|
||||||
|
"cascade_completions=%d unlocked=%u otch_appends=%d roll_draws=%d failures=%d depth=%d "
|
||||||
|
"name_unreadable=%d",
|
||||||
|
compare ? "compare" : "replace", static_cast<unsigned>(r.steps.size()), model_completions,
|
||||||
|
r.overbudget, cascade_possible ? 1 : 0, cascade_ok ? 1 : 0, cc.completions,
|
||||||
|
static_cast<unsigned>(cc.unlocked.size()), cc.observed_appends, cc.roll_draws,
|
||||||
|
cc.cascade_failures, cc.depth_exceeded ? 1 : 0, cc.name_unreadable ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool research_config(const char* key, const char* value, std::string* err) {
|
||||||
|
if (std::strcmp(key, "research.replace_cascade") == 0) {
|
||||||
|
if (std::strcmp(value, "on") == 0 || std::strcmp(value, "1") == 0) {
|
||||||
|
g_env.replace_cascade = true;
|
||||||
|
} else if (std::strcmp(value, "off") == 0 || std::strcmp(value, "0") == 0) {
|
||||||
|
g_env.replace_cascade = false;
|
||||||
|
} else if (err) {
|
||||||
|
*err = "expected on|off";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_research(std::uintptr_t exe_base, void (*log_line)(const char* line)) {
|
void init_research(std::uintptr_t exe_base, void (*log_line)(const char* line)) {
|
||||||
g_env.exe_base = exe_base;
|
g_env.exe_base = exe_base;
|
||||||
g_env.log_line = log_line;
|
g_env.log_line = log_line;
|
||||||
g_env.cost = reinterpret_cast<CostFn>(exe_base + A::TechTree_Cost);
|
g_env.cost = reinterpret_cast<CostFn>(exe_base + A::TechTree_Cost);
|
||||||
logf("research: ProcessResearch hook ready (Cost=%p, node=0x%x, rng=0x%x, fpu_cw=0x%04x)",
|
logf("research: ProcessResearch hook ready (Cost=%p, node=0x%x, rng=0x%x, fpu_cw=0x%04x, "
|
||||||
|
"replace_cascade=%s)",
|
||||||
reinterpret_cast<void*>(g_env.cost), static_cast<unsigned>(kNodeSize),
|
reinterpret_cast<void*>(g_env.cost), static_cast<unsigned>(kNodeSize),
|
||||||
static_cast<unsigned>(kRngSize), fpu_control_word());
|
static_cast<unsigned>(kRngSize), fpu_control_word(),
|
||||||
|
g_env.replace_cascade ? "on" : "off");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace shim::hooks
|
} // namespace shim::hooks
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,13 @@
|
||||||
// and the rebellion branch cancels the research outright. Its tech-effect field writes are B2's
|
// and the rebellion branch cancels the research outright. Its tech-effect field writes are B2's
|
||||||
// milestone and remain what the `player` guard reports.
|
// milestone and remain what the `player` guard reports.
|
||||||
//
|
//
|
||||||
// REPLACE mode runs none of the cascade: there, every pointer is live game memory and applying
|
// REPLACE mode runs none of the cascade by default: there, every pointer is live game memory and
|
||||||
// half of the callback would leave the player in a state no code path produces.
|
// applying half of the callback would leave the player in a state no code path produces.
|
||||||
|
// `research.replace_cascade=on` opts a replace run into the TechTree half of it -- the four
|
||||||
|
// TechNode words SetResearched stamps and the tree's completion-order counter -- and nothing of
|
||||||
|
// the ServerPlayer half. That is deliberate and it is measurable: the same binary run twice with
|
||||||
|
// the flag off and on gives two autosaves whose leaf difference IS the cascade's contribution,
|
||||||
|
// and what both still differ from the original by is the callback's effect on the player.
|
||||||
//
|
//
|
||||||
// The effective cost of a node is taken from the game's own TechTree::Cost, which is read-only --
|
// The effective cost of a node is taken from the game's own TechTree::Cost, which is read-only --
|
||||||
// the cost multiplier is a separate, lower-confidence formula and not what this milestone is
|
// the cost multiplier is a separate, lower-confidence formula and not what this milestone is
|
||||||
|
|
@ -52,6 +57,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -94,13 +100,16 @@ struct TechTreeProcessResearchHook {
|
||||||
"table, so the message is composed from node indices instead and is not the "
|
"table, so the message is composed from node indices instead and is not the "
|
||||||
"game's text",
|
"game's text",
|
||||||
"region:events");
|
"region:events");
|
||||||
c.unmodelled("TechTree::SetResearched in REPLACE mode: nothing of it runs",
|
c.unmodelled("TechTree::SetResearched in REPLACE mode: only its TechTree half runs, and "
|
||||||
|
"only when research.replace_cascade=on",
|
||||||
trace::Risk::High,
|
trace::Risk::High,
|
||||||
"the cascade is compare-mode only. In replace mode every pointer is live "
|
"with the flag OFF (the default) nothing of the cascade runs, so a replace "
|
||||||
"game memory, and applying half of OnTechResearched -- the observed-tech "
|
"run leaves the completed node unstamped and no tech unlocked. With it ON, "
|
||||||
"append and the research-event roll, but not the tech-effect field writes -- "
|
"the four TechNode words (costRP, turnAvailable, turnResearched, order) and "
|
||||||
"would leave the player in a state no code path produces. A replace run "
|
"the tree's completion-order counter are written live, and the ServerPlayer "
|
||||||
"therefore still leaves the completed node unstamped and no tech unlocked",
|
"half is still not: no event is posted, no ObservedTech element is appended "
|
||||||
|
"and no tech effect is applied. Neither setting is a full displacement of "
|
||||||
|
"the completion path; the pair measures where the boundary is",
|
||||||
"guard:player, guard:tree_header");
|
"guard:player, guard:tree_header");
|
||||||
c.unmodelled("ServerPlayer::OnTechResearched's tech effects: the ~90 hard-coded "
|
c.unmodelled("ServerPlayer::OnTechResearched's tech effects: the ~90 hard-coded "
|
||||||
"ServerPlayer field writes, the plague-cure masks, the design-option "
|
"ServerPlayer field writes, the plague-cure masks, the design-option "
|
||||||
|
|
@ -146,6 +155,10 @@ struct TechTreeProcessResearchHook {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// `research.replace_cascade=on|off` (default off). Returns false if `key` is not ours.
|
||||||
|
// Call BEFORE init_research so the banner reports the value that is in force.
|
||||||
|
bool research_config(const char* key, const char* value, std::string* err);
|
||||||
|
|
||||||
// Process facts the hook needs (exe base for the RVAs, a line logger). Call once before
|
// Process facts the hook needs (exe base for the RVAs, a line logger). Call once before
|
||||||
// installing.
|
// installing.
|
||||||
void init_research(std::uintptr_t exe_base, void (*log_line)(const char* line));
|
void init_research(std::uintptr_t exe_base, void (*log_line)(const char* line));
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,9 @@ Config ReadConfig() {
|
||||||
} else if (shim::hooks::ai_orders_config(p, val, &err)) {
|
} else if (shim::hooks::ai_orders_config(p, val, &err)) {
|
||||||
if (!err.empty()) Log("config: %s=%s rejected (%s)", p, val, err.c_str());
|
if (!err.empty()) Log("config: %s=%s rejected (%s)", p, val, err.c_str());
|
||||||
else Log("config: %s=%s", p, val);
|
else Log("config: %s=%s", p, val);
|
||||||
|
} else if (shim::hooks::research_config(p, val, &err)) {
|
||||||
|
if (!err.empty()) Log("config: %s=%s rejected (%s)", p, val, err.c_str());
|
||||||
|
else Log("config: %s=%s", p, val);
|
||||||
} else if (shim::hooks::watch_apply_config(p, val, &err)) {
|
} else if (shim::hooks::watch_apply_config(p, val, &err)) {
|
||||||
if (!err.empty()) Log("config: %s=%s rejected (%s)", p, val, err.c_str());
|
if (!err.empty()) Log("config: %s=%s rejected (%s)", p, val, err.c_str());
|
||||||
else Log("config: %s=%s", p, val);
|
else Log("config: %s=%s", p, val);
|
||||||
|
|
|
||||||
35
src/shim/shim.cfg.crcompare
Normal file
35
src/shim/shim.cfg.crcompare
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Lane CR, crcompare. ProcessResearch in compare; every other registered hook named off.
|
||||||
|
# research.replace_cascade=off.
|
||||||
|
# exhaustive
|
||||||
|
hooks=trace
|
||||||
|
hook.Game::EncounterDetect::AssignContacts=off
|
||||||
|
hook.Game::EncounterDetect::ProcessTeamRecord=off
|
||||||
|
hook.Game::SVSOSlaversRefuel::UpdateDifficultyTier=off
|
||||||
|
hook.Game::SVSOSwarmQueen::OnTurnBegin=off
|
||||||
|
hook.Game::SVSOSwarmQueen::RegisterHives=off
|
||||||
|
hook.Game::SVSOSwarmQueen::TickHives=off
|
||||||
|
hook.Game::SectionDictionary::SectionDictionary=off
|
||||||
|
hook.Game::ServerPlayer::ComputeBudget=off
|
||||||
|
hook.Game::ServerPlayer::OnTechResearched=off
|
||||||
|
hook.Game::ServerPlayer::ProcessTurn=off
|
||||||
|
hook.Game::ServerSystem::ComputeTotalOutput=off
|
||||||
|
hook.Game::ServerSystem::GroupOutput=off
|
||||||
|
hook.Game::ServerSystem::ProcessTurn=off
|
||||||
|
hook.Game::StrategyApp::RunAI=off
|
||||||
|
hook.Game::StrategyHost::Autosave=off
|
||||||
|
hook.Game::StrategyServer::ApplyEncounterResult=off
|
||||||
|
hook.Game::StrategyServer::BeginProcessTurn=off
|
||||||
|
hook.Game::StrategyServer::MoveFleet=off
|
||||||
|
hook.Game::StrategyServer::NodeLineDecay=off
|
||||||
|
hook.Game::StrategyServer::OnAllCombatDone_Tail=off
|
||||||
|
hook.Game::StrategyServer::ProcessFleetMovement=off
|
||||||
|
hook.Game::StrategyServer::ProcessNodeSpaceTravel=off
|
||||||
|
hook.Game::StrategyServer::ProcessTurn=off
|
||||||
|
hook.Game::WeaponDictionary::Init=off
|
||||||
|
hook.Mars::GlobalConsts::LoadFile=off
|
||||||
|
hook.Mars::RNG::Seed=off
|
||||||
|
hook.Game::TechTree::ProcessResearch=compare
|
||||||
|
research.replace_cascade=off
|
||||||
|
trace.path=C:\SOTS\shim.trace.jsonl
|
||||||
|
trace.inline_max=256
|
||||||
|
trace.flush=always
|
||||||
6
src/shim/shim.cfg.croff
Normal file
6
src/shim/shim.cfg.croff
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Lane CR, the rule-19 control. Same proxy DLL as every measured CR run, same guest, same save,
|
||||||
|
# same click path -- `hooks=off` installs NOTHING (not even the M0 asm stub), so a difference
|
||||||
|
# between this run's autosaves and a measured run's is the instrument and nothing else.
|
||||||
|
# `# exhaustive` is deliberately absent: it is a claim about a `hooks=trace` hook set, and there
|
||||||
|
# is no hook set here to be exhaustive about.
|
||||||
|
hooks=off
|
||||||
35
src/shim/shim.cfg.crreplace0
Normal file
35
src/shim/shim.cfg.crreplace0
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Lane CR, crreplace0. ProcessResearch in replace; every other registered hook named off.
|
||||||
|
# research.replace_cascade=off.
|
||||||
|
# exhaustive
|
||||||
|
hooks=trace
|
||||||
|
hook.Game::EncounterDetect::AssignContacts=off
|
||||||
|
hook.Game::EncounterDetect::ProcessTeamRecord=off
|
||||||
|
hook.Game::SVSOSlaversRefuel::UpdateDifficultyTier=off
|
||||||
|
hook.Game::SVSOSwarmQueen::OnTurnBegin=off
|
||||||
|
hook.Game::SVSOSwarmQueen::RegisterHives=off
|
||||||
|
hook.Game::SVSOSwarmQueen::TickHives=off
|
||||||
|
hook.Game::SectionDictionary::SectionDictionary=off
|
||||||
|
hook.Game::ServerPlayer::ComputeBudget=off
|
||||||
|
hook.Game::ServerPlayer::OnTechResearched=off
|
||||||
|
hook.Game::ServerPlayer::ProcessTurn=off
|
||||||
|
hook.Game::ServerSystem::ComputeTotalOutput=off
|
||||||
|
hook.Game::ServerSystem::GroupOutput=off
|
||||||
|
hook.Game::ServerSystem::ProcessTurn=off
|
||||||
|
hook.Game::StrategyApp::RunAI=off
|
||||||
|
hook.Game::StrategyHost::Autosave=off
|
||||||
|
hook.Game::StrategyServer::ApplyEncounterResult=off
|
||||||
|
hook.Game::StrategyServer::BeginProcessTurn=off
|
||||||
|
hook.Game::StrategyServer::MoveFleet=off
|
||||||
|
hook.Game::StrategyServer::NodeLineDecay=off
|
||||||
|
hook.Game::StrategyServer::OnAllCombatDone_Tail=off
|
||||||
|
hook.Game::StrategyServer::ProcessFleetMovement=off
|
||||||
|
hook.Game::StrategyServer::ProcessNodeSpaceTravel=off
|
||||||
|
hook.Game::StrategyServer::ProcessTurn=off
|
||||||
|
hook.Game::WeaponDictionary::Init=off
|
||||||
|
hook.Mars::GlobalConsts::LoadFile=off
|
||||||
|
hook.Mars::RNG::Seed=off
|
||||||
|
hook.Game::TechTree::ProcessResearch=replace
|
||||||
|
research.replace_cascade=off
|
||||||
|
trace.path=C:\SOTS\shim.trace.jsonl
|
||||||
|
trace.inline_max=256
|
||||||
|
trace.flush=always
|
||||||
35
src/shim/shim.cfg.crreplace1
Normal file
35
src/shim/shim.cfg.crreplace1
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Lane CR, crreplace1. ProcessResearch in replace; every other registered hook named off.
|
||||||
|
# research.replace_cascade=on.
|
||||||
|
# exhaustive
|
||||||
|
hooks=trace
|
||||||
|
hook.Game::EncounterDetect::AssignContacts=off
|
||||||
|
hook.Game::EncounterDetect::ProcessTeamRecord=off
|
||||||
|
hook.Game::SVSOSlaversRefuel::UpdateDifficultyTier=off
|
||||||
|
hook.Game::SVSOSwarmQueen::OnTurnBegin=off
|
||||||
|
hook.Game::SVSOSwarmQueen::RegisterHives=off
|
||||||
|
hook.Game::SVSOSwarmQueen::TickHives=off
|
||||||
|
hook.Game::SectionDictionary::SectionDictionary=off
|
||||||
|
hook.Game::ServerPlayer::ComputeBudget=off
|
||||||
|
hook.Game::ServerPlayer::OnTechResearched=off
|
||||||
|
hook.Game::ServerPlayer::ProcessTurn=off
|
||||||
|
hook.Game::ServerSystem::ComputeTotalOutput=off
|
||||||
|
hook.Game::ServerSystem::GroupOutput=off
|
||||||
|
hook.Game::ServerSystem::ProcessTurn=off
|
||||||
|
hook.Game::StrategyApp::RunAI=off
|
||||||
|
hook.Game::StrategyHost::Autosave=off
|
||||||
|
hook.Game::StrategyServer::ApplyEncounterResult=off
|
||||||
|
hook.Game::StrategyServer::BeginProcessTurn=off
|
||||||
|
hook.Game::StrategyServer::MoveFleet=off
|
||||||
|
hook.Game::StrategyServer::NodeLineDecay=off
|
||||||
|
hook.Game::StrategyServer::OnAllCombatDone_Tail=off
|
||||||
|
hook.Game::StrategyServer::ProcessFleetMovement=off
|
||||||
|
hook.Game::StrategyServer::ProcessNodeSpaceTravel=off
|
||||||
|
hook.Game::StrategyServer::ProcessTurn=off
|
||||||
|
hook.Game::WeaponDictionary::Init=off
|
||||||
|
hook.Mars::GlobalConsts::LoadFile=off
|
||||||
|
hook.Mars::RNG::Seed=off
|
||||||
|
hook.Game::TechTree::ProcessResearch=replace
|
||||||
|
research.replace_cascade=on
|
||||||
|
trace.path=C:\SOTS\shim.trace.jsonl
|
||||||
|
trace.inline_max=256
|
||||||
|
trace.flush=always
|
||||||
Loading…
Add table
Reference in a new issue