From 1ca0e1dd5a2cf60a3dc418d7c140af76ca231ab0 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 30 Apr 2026 10:35:20 -0400 Subject: [PATCH] =?UTF-8?q?feat(@projects):=20=E2=9C=A8=20add=20gd-rust=20?= =?UTF-8?q?bridge=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .project/designs/app/src/App.tsx | 2 + .../designs/app/src/pages/GdRustBridge.tsx | 582 +++ .project/designs/app/src/pages/Index.tsx | 5 +- .project/designs/app/tsconfig.json | 4 +- .project/designs/app/vite.config.ts | 2 + .../p2-45-elimination-reconciliation.md | 8 +- .project/reports/gd-rust-relationships.json | 3563 +++++++++++++++++ .../games/age-of-dwarves/docs/HEX_GEOMETRY.md | 1 + public/games/age-of-dwarves/manifest.json | 3 - public/resources/buildings/airfield.json | 6 +- public/resources/buildings/tank_yard.json | 2 +- public/resources/buildings/walker_yard.json | 3 +- public/resources/buildings/zeppelin_dock.json | 1 - .../engine/tests/unit/test_victory_manager.gd | 100 +- src/simulator/api-gdext/src/lib.rs | 100 + tools/gd-rust-relationships.py | 48 +- 16 files changed, 4392 insertions(+), 38 deletions(-) create mode 100644 .project/designs/app/src/pages/GdRustBridge.tsx create mode 100644 .project/reports/gd-rust-relationships.json diff --git a/.project/designs/app/src/App.tsx b/.project/designs/app/src/App.tsx index e320e63c..c7805694 100644 --- a/.project/designs/app/src/App.tsx +++ b/.project/designs/app/src/App.tsx @@ -19,6 +19,7 @@ import { StatisticsPage } from "./pages/Statistics"; import { EndGameSummaryPage } from "./pages/EndGameSummary"; import { PastGamesPage } from "./pages/PastGames"; import { ReplayPage } from "./pages/Replay"; +import { GdRustBridgePage } from "./pages/GdRustBridge"; export function App(): React.ReactElement { return ( @@ -44,6 +45,7 @@ export function App(): React.ReactElement { } /> } /> } /> + } /> ); diff --git a/.project/designs/app/src/pages/GdRustBridge.tsx b/.project/designs/app/src/pages/GdRustBridge.tsx new file mode 100644 index 00000000..b4166ddb --- /dev/null +++ b/.project/designs/app/src/pages/GdRustBridge.tsx @@ -0,0 +1,582 @@ +import { useMemo, useState } from "react"; +import { Link } from "react-router-dom"; +import styled from "styled-components"; +import { t } from "../theme"; +import reportData from "@reports/gd-rust-relationships.json"; + +// ── types ───────────────────────────────────────────────────────────────── + +interface CallerLine { + file: string; + line: number; +} + +interface ClassEntry { + name: string; + rustStruct: string; + base: string | null; + file: string; + line: number; + funcCount: number; + callerFiles: string[]; + callerLines: CallerLine[]; +} + +interface ReportData { + generatedAt: string; + classes: ClassEntry[]; + gdClassNames: Record; + collisions: string[]; + crateDeps: Record; +} + +const data = reportData as ReportData; + +// ── styled ──────────────────────────────────────────────────────────────── + +const Page = styled.div` + min-height: 100vh; + background: ${t.bg.deepest}; + color: ${t.text.primary}; + font-family: "Inter", system-ui, sans-serif; + padding: 24px 32px; +`; + +const BackLink = styled(Link)` + color: ${t.text.muted}; + font-size: 12px; + text-decoration: none; + font-family: ${t.font.mono}; + &:hover { color: ${t.accent.gold}; } +`; + +const Header = styled.header` + margin: 10px 0 20px; + h1 { + font-family: "Cinzel", serif; + color: ${t.text.title}; + margin: 0 0 4px; + font-size: 26px; + } + p { + color: ${t.text.muted}; + margin: 0; + font-size: 12px; + font-family: ${t.font.mono}; + } +`; + +const Stats = styled.div` + display: flex; + gap: 24px; + margin-bottom: 20px; +`; + +const Stat = styled.div` + background: ${t.bg.panel}; + border: 1px solid ${t.border.panel}; + border-radius: 4px; + padding: 10px 16px; + font-size: 12px; + color: ${t.text.muted}; + span { display: block; font-size: 22px; color: ${t.accent.gold}; font-family: ${t.font.mono}; } +`; + +const Tabs = styled.nav` + display: flex; + gap: 4px; + margin-bottom: 20px; + border-bottom: 1px solid ${t.bg.raised}; +`; + +const Tab = styled.button<{ $active: boolean }>` + background: ${p => p.$active ? t.bg.raised : "transparent"}; + border: none; + border-bottom: 2px solid ${p => p.$active ? t.accent.gold : "transparent"}; + color: ${p => p.$active ? t.text.primary : t.text.muted}; + cursor: pointer; + font-size: 13px; + padding: 8px 16px; + margin-bottom: -1px; + &:hover { color: ${t.text.primary}; } +`; + +const FilterRow = styled.div` + display: flex; + gap: 10px; + margin-bottom: 14px; + align-items: center; +`; + +const SearchInput = styled.input` + background: ${t.bg.panel}; + border: 1px solid ${t.border.panel}; + border-radius: 3px; + color: ${t.text.primary}; + font-family: ${t.font.mono}; + font-size: 12px; + padding: 6px 10px; + width: 260px; + &::placeholder { color: ${t.text.disabled}; } + &:focus { outline: none; border-color: ${t.accent.gold}; } +`; + +const Select = styled.select` + background: ${t.bg.panel}; + border: 1px solid ${t.border.panel}; + border-radius: 3px; + color: ${t.text.primary}; + font-size: 12px; + padding: 6px 10px; + cursor: pointer; +`; + +const Table = styled.table` + width: 100%; + border-collapse: collapse; + font-size: 12px; +`; + +const Th = styled.th<{ $align?: "left" | "right" | "center" }>` + text-align: ${p => p.$align ?? "left"}; + color: ${t.text.muted}; + font-weight: 600; + padding: 6px 10px; + border-bottom: 1px solid ${t.border.divider}; + cursor: pointer; + white-space: nowrap; + user-select: none; + &:hover { color: ${t.accent.gold}; } +`; + +const Tr = styled.tr<{ $selected?: boolean }>` + background: ${p => p.$selected ? t.bg.listSel : "transparent"}; + &:hover { background: ${t.bg.raised}; } + cursor: pointer; +`; + +const Td = styled.td<{ $align?: "left" | "right" | "center"; $mono?: boolean }>` + text-align: ${p => p.$align ?? "left"}; + font-family: ${p => p.$mono ? t.font.mono : "inherit"}; + padding: 6px 10px; + border-bottom: 1px solid ${t.border.divider}; + color: ${t.text.secondary}; + white-space: nowrap; +`; + +const Code = styled.code` + font-family: ${t.font.mono}; + color: ${t.accent.goldRes}; + font-size: 11px; +`; + +const Badge = styled.span<{ $variant?: "unused" | "normal" }>` + background: ${p => p.$variant === "unused" ? t.sem.negative + "33" : t.accent.gold + "22"}; + color: ${p => p.$variant === "unused" ? t.sem.negative : t.accent.gold}; + font-size: 10px; + padding: 1px 6px; + border-radius: 10px; + font-family: ${t.font.mono}; +`; + +// ── detail panel ────────────────────────────────────────────────────────── + +const DetailPanel = styled.div` + background: ${t.bg.panel}; + border: 1px solid ${t.border.panel}; + border-radius: 4px; + padding: 18px 20px; + margin-top: 16px; +`; + +const DetailTitle = styled.h3` + font-family: ${t.font.mono}; + color: ${t.text.title}; + margin: 0 0 12px; + font-size: 15px; +`; + +const CallerList = styled.ul` + list-style: none; + padding: 0; + margin: 0; +`; + +const CallerItem = styled.li` + display: flex; + gap: 12px; + padding: 5px 0; + border-bottom: 1px solid ${t.border.divider}; + font-family: ${t.font.mono}; + font-size: 11px; + color: ${t.text.muted}; + &:last-child { border-bottom: none; } +`; + +const CallerFile = styled.span` + color: ${t.accent.science}; + flex: 1; +`; + +const CallerLines = styled.span` + color: ${t.text.secondary}; +`; + +// ── dep graph ──────────────────────────────────────────────────────────── + +const DepGrid = styled.div` + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 10px; +`; + +const DepCard = styled.div<{ $isBridge?: boolean }>` + background: ${p => p.$isBridge ? t.bg.raised : t.bg.panel}; + border: 1px solid ${p => p.$isBridge ? t.border.focus : t.border.panel}; + border-radius: 4px; + padding: 12px 14px; +`; + +const DepCardTitle = styled.div` + font-family: ${t.font.mono}; + font-size: 12px; + color: ${t.accent.gold}; + margin-bottom: 6px; +`; + +const DepCardDeps = styled.ul` + list-style: none; + padding: 0; + margin: 0; +`; + +const DepCardDep = styled.li` + font-family: ${t.font.mono}; + font-size: 11px; + color: ${t.text.muted}; + padding: 2px 0; + &::before { content: "→ "; color: ${t.accent.goldRes}; } +`; + +// ── gd-class tab ───────────────────────────────────────────────────────── + +const GdList = styled.div` + display: grid; + grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); + gap: 6px; +`; + +const GdRow = styled.div<{ $collision?: boolean }>` + display: flex; + gap: 10px; + background: ${p => p.$collision ? t.sem.negative + "18" : t.bg.panel}; + border: 1px solid ${p => p.$collision ? t.sem.negative + "55" : t.border.panel}; + border-radius: 3px; + padding: 6px 10px; + font-family: ${t.font.mono}; + font-size: 11px; +`; + +const GdName = styled.span` + color: ${t.accent.sage}; + min-width: 180px; +`; + +const GdFile = styled.span` + color: ${t.text.muted}; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +`; + +// ── sort helpers ────────────────────────────────────────────────────────── + +type SortKey = "name" | "callerFiles" | "funcCount"; + +function sortClasses(list: ClassEntry[], key: SortKey, asc: boolean) { + return [...list].sort((a, b) => { + let va: string | number, vb: string | number; + if (key === "name") { va = a.name; vb = b.name; } + else if (key === "callerFiles") { va = a.callerFiles.length; vb = b.callerFiles.length; } + else { va = a.funcCount; vb = b.funcCount; } + if (va < vb) return asc ? -1 : 1; + if (va > vb) return asc ? 1 : -1; + return 0; + }); +} + +// ── tabs ────────────────────────────────────────────────────────────────── + +type TabId = "surface" | "callers" | "deps" | "gd-classes"; + +function SurfaceTab() { + const [search, setSearch] = useState(""); + const [filter, setFilter] = useState<"all" | "used" | "unused">("all"); + const [sortKey, setSortKey] = useState("callerFiles"); + const [sortAsc, setSortAsc] = useState(false); + const [selected, setSelected] = useState(null); + + const classes = useMemo(() => { + let list = data.classes; + if (search) list = list.filter(c => c.name.toLowerCase().includes(search.toLowerCase())); + if (filter === "used") list = list.filter(c => c.callerFiles.length > 0); + if (filter === "unused") list = list.filter(c => c.callerFiles.length === 0); + return sortClasses(list, sortKey, sortAsc); + }, [search, filter, sortKey, sortAsc]); + + const selectedClass = selected ? data.classes.find(c => c.name === selected) ?? null : null; + + function toggleSort(key: SortKey) { + if (sortKey === key) setSortAsc(a => !a); + else { setSortKey(key); setSortAsc(false); } + } + + function sortArrow(key: SortKey) { + if (sortKey !== key) return ""; + return sortAsc ? " ↑" : " ↓"; + } + + return ( + <> + + setSearch(e.target.value)} + /> + + + + + + + + + + + + + + + {classes.map(c => ( + setSelected(selected === c.name ? null : c.name)} + > + + + + + + + ))} + +
toggleSort("name")}>Godot class{sortArrow("name")}base toggleSort("funcCount")}>#[func]{sortArrow("funcCount")} toggleSort("callerFiles")}>GD files{sortArrow("callerFiles")}Rust source
+ {c.name} + {c.callerFiles.length === 0 && ( + <> unused + )} + {c.base ?? "—"}{c.funcCount} + {c.callerFiles.length} + + {c.file}:{c.line} +
+ + {selectedClass && ( + + {selectedClass.name} +
+ Rust struct {selectedClass.rustStruct} · base {selectedClass.base ?? "—"} + {" · "}{selectedClass.funcCount} #[func] · defined at {selectedClass.file}:{selectedClass.line} +
+ {selectedClass.callerFiles.length === 0 ? ( +
No GDScript references found.
+ ) : ( + + {selectedClass.callerFiles.map(file => { + const lines = selectedClass.callerLines + .filter(cl => cl.file === file) + .map(cl => cl.line) + .slice(0, 10); + return ( + + {file} + L{lines.join(", L")} + + ); + })} + + )} +
+ )} + + ); +} + +function CallersTab() { + const [search, setSearch] = useState(""); + const sorted = useMemo(() => { + const list = data.classes.filter(c => c.callerFiles.length > 0); + if (search) return list.filter(c => + c.name.toLowerCase().includes(search.toLowerCase()) || + c.callerFiles.some(f => f.toLowerCase().includes(search.toLowerCase())) + ); + return list; + }, [search]); + + return ( + <> + + setSearch(e.target.value)} + /> + {sorted.length} classes + + {sorted.map(c => ( + + + {c.name} + + {c.callerFiles.length} file{c.callerFiles.length !== 1 ? "s" : ""} + + + + {c.callerFiles.map(file => { + const lines = c.callerLines.filter(cl => cl.file === file).map(cl => cl.line).slice(0, 12); + return ( + + {file} + L{lines.join(", L")}{c.callerLines.filter(cl => cl.file === file).length > 12 ? "…" : ""} + + ); + })} + + + ))} + + ); +} + +function DepsTab() { + const BRIDGES = new Set(["api-gdext", "api-wasm"]); + const entries = Object.entries(data.crateDeps).sort((a, b) => { + const ab = BRIDGES.has(a[0]), bb = BRIDGES.has(b[0]); + if (ab && !bb) return -1; + if (!ab && bb) return 1; + return b[1].length - a[1].length; + }); + + return ( + <> +
+ {Object.keys(data.crateDeps).length} workspace crates. + Bridge crates (api-gdext, api-wasm) highlighted. +
+ + {entries.map(([crate, deps]) => ( + + {crate} + {deps.length === 0 ? ( +
no internal deps
+ ) : ( + + {deps.map(d => {d})} + + )} +
+ ))} +
+ + ); +} + +function GdClassesTab() { + const [search, setSearch] = useState(""); + const collisionSet = new Set(data.collisions); + const entries = useMemo(() => { + const all = Object.entries(data.gdClassNames); + return search + ? all.filter(([n, f]) => n.toLowerCase().includes(search.toLowerCase()) || f.toLowerCase().includes(search.toLowerCase())) + : all; + }, [search]); + + return ( + <> + + setSearch(e.target.value)} + /> + {data.collisions.length > 0 && ( + ⚠ {data.collisions.length} name collision{data.collisions.length !== 1 ? "s" : ""} + )} + {entries.length} classes + + + {entries.map(([name, file]) => ( + + {name} + {file} + {collisionSet.has(name) && collision} + + ))} + + + ); +} + +// ── page ────────────────────────────────────────────────────────────────── + +const TAB_LABELS: Record = { + surface: "Binding surface", + callers: "Per-class callers", + deps: "Crate deps", + "gd-classes": "GD class_names", +}; + +export function GdRustBridgePage(): React.ReactElement { + const [tab, setTab] = useState("surface"); + const ts = new Date(data.generatedAt).toLocaleString(); + const usedCount = data.classes.filter(c => c.callerFiles.length > 0).length; + const totalGdRefs = data.classes.reduce((s, c) => s + c.callerFiles.length, 0); + + return ( + + ← back +
+

GDScript ↔ Rust Bridge

+

Generated {ts} · re-run: python3 tools/gd-rust-relationships.py

+
+ + + {data.classes.length}exported classes + {usedCount}referenced from GD + {totalGdRefs}total GD–file links + {Object.keys(data.crateDeps).length}workspace crates + {Object.keys(data.gdClassNames).length}GD class_names + + + + {(Object.keys(TAB_LABELS) as TabId[]).map(id => ( + setTab(id)}> + {TAB_LABELS[id]} + + ))} + + + {tab === "surface" && } + {tab === "callers" && } + {tab === "deps" && } + {tab === "gd-classes" && } +
+ ); +} diff --git a/.project/designs/app/src/pages/Index.tsx b/.project/designs/app/src/pages/Index.tsx index da9ae45a..9d4d9f09 100644 --- a/.project/designs/app/src/pages/Index.tsx +++ b/.project/designs/app/src/pages/Index.tsx @@ -64,8 +64,9 @@ const routes = [ { path: "/promotion", label: "★ Promotion Picker — grid, lock states, prereqs" }, { path: "/stats", label: "📊 Statistics — Demographics, Graphs, Rankings, Histories" }, { path: "/end-game", label: "🏆 End-of-Game Summary — outcome, standings, awards, score graph" }, - { path: "/past-games",label: "📚 Past Games — archived game cards, filters, sorts" }, - { path: "/replay", label: "⏯ Replay Viewer — scrubber, event ticker, stats overlay" }, + { path: "/past-games", label: "📚 Past Games — archived game cards, filters, sorts" }, + { path: "/replay", label: "⏯ Replay Viewer — scrubber, event ticker, stats overlay" }, + { path: "/gd-rust", label: "🦀 GD ↔ Rust Bridge — binding surface, callers, crate deps" }, ]; export function IndexPage(): React.ReactElement { diff --git a/.project/designs/app/tsconfig.json b/.project/designs/app/tsconfig.json index 5b49ce81..05e07d97 100644 --- a/.project/designs/app/tsconfig.json +++ b/.project/designs/app/tsconfig.json @@ -18,11 +18,13 @@ "@game-data/*": ["../../../public/games/age-of-dwarves/data/*"], "@game-assets/*": ["../../../public/games/age-of-dwarves/assets/*"], "@resources/*": ["../../../public/resources/*"], - "@audio-alts/*": ["../../../.local/audio-alternatives/*"] + "@audio-alts/*": ["../../../.local/audio-alternatives/*"], + "@reports/*": ["../../reports/*"] } }, "include": [ "src", + "../../reports/gd-rust-relationships.json", "../../../public/resources/audio/library.json", "../../../public/games/age-of-dwarves/data/audio/manifest.json", "../../../public/games/age-of-dwarves/data/audio/pools.json" diff --git a/.project/designs/app/vite.config.ts b/.project/designs/app/vite.config.ts index 3c86e51c..82766c5d 100644 --- a/.project/designs/app/vite.config.ts +++ b/.project/designs/app/vite.config.ts @@ -12,6 +12,7 @@ export default defineConfig({ "@resources": path.resolve(__dirname, "../../../public/resources"), "@audio-alts": path.resolve(__dirname, "../../../.local/audio-alternatives"), "@audio-staging": path.resolve(__dirname, "../../../.local/audio-staging"), + "@reports": path.resolve(__dirname, "../../reports"), }, }, server: { @@ -24,6 +25,7 @@ export default defineConfig({ path.resolve(__dirname, "../../../public"), path.resolve(__dirname, "../../../.local/audio-alternatives"), path.resolve(__dirname, "../../../.local/audio-staging"), + path.resolve(__dirname, "../../reports"), ], }, watch: { diff --git a/.project/objectives/p2-45-elimination-reconciliation.md b/.project/objectives/p2-45-elimination-reconciliation.md index a6014f5e..adcf1abe 100644 --- a/.project/objectives/p2-45-elimination-reconciliation.md +++ b/.project/objectives/p2-45-elimination-reconciliation.md @@ -2,10 +2,16 @@ id: p2-45 title: "Player elimination reconciliation — emit `player_eliminated` on every transition" priority: p2 -status: missing +status: done scope: game1 updated_at: 2026-04-30 assigned_by: shipwright +evidence: + - "src/game/engine/src/entities/player.gd:36 — `is_eliminated: bool` flag added (default false), latches forever once set" + - "src/game/engine/src/modules/victory/victory_manager.gd:54 — `_reconcile_eliminations()` called on every check_all() at turn-end; sweeps all players, sets is_eliminated + emits EventBus.player_eliminated for any newly-eliminated player exactly once" + - "src/game/engine/src/modules/combat/combat_utils.gd:139 + src/game/engine/src/entities/combat_utils.gd:138 — both city-capture paths now check the latch before emitting and set it themselves; dedupes against the reconciliation sweep" + - "src/game/engine/tests/unit/test_victory_manager.gd — 5/5 GUT tests passing on apricot (rehydrated from stub): test_reconciliation_emits_for_eliminated_player, test_reconciliation_latches_is_eliminated_flag, test_second_sweep_is_silent, test_survivor_does_not_trigger, test_already_eliminated_flag_skips_emit" + - "Regression-clean: test_audio_manager.gd 18/18 + test_chronicle_coverage.gd all-pass after the change (apricot headless, 2026-04-30)" --- ## Summary diff --git a/.project/reports/gd-rust-relationships.json b/.project/reports/gd-rust-relationships.json new file mode 100644 index 00000000..fd938b3c --- /dev/null +++ b/.project/reports/gd-rust-relationships.json @@ -0,0 +1,3563 @@ +{ + "generatedAt": "2026-04-30T14:29:32.516762Z", + "classes": [ + { + "name": "GdAiController", + "rustStruct": "GdAiController", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/ai.rs", + "line": 577, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/tests/auto_play.gd", + "src/game/engine/src/autoloads/game_state.gd", + "src/game/engine/src/entities/auto_play.gd", + "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "src/game/engine/tests/integration/test_ai_simulation.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/auto_play.gd", + "line": 1195 + }, + { + "file": "src/game/engine/src/autoloads/game_state.gd", + "line": 143 + }, + { + "file": "src/game/engine/src/autoloads/game_state.gd", + "line": 145 + }, + { + "file": "src/game/engine/src/autoloads/game_state.gd", + "line": 151 + }, + { + "file": "src/game/engine/src/autoloads/game_state.gd", + "line": 156 + }, + { + "file": "src/game/engine/src/autoloads/game_state.gd", + "line": 158 + }, + { + "file": "src/game/engine/src/entities/auto_play.gd", + "line": 1203 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 7 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 126 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 127 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "line": 84 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "line": 103 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "line": 118 + }, + { + "file": "src/game/engine/tests/integration/test_ai_simulation.gd", + "line": 4 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 26 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 104 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 145 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 348 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 352 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 353 + } + ] + }, + { + "name": "GdAtmosphericChemistry", + "rustStruct": "GdAtmosphericChemistry", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 381, + "funcCount": 2, + "callerFiles": [ + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 20 + } + ] + }, + { + "name": "GdCity", + "rustStruct": "GdCity", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 976, + "funcCount": 5, + "callerFiles": [ + "src/game/engine/scenes/city/city_buildable_helper.gd", + "src/game/engine/scenes/hud/crafting_complete_modal.gd", + "src/game/engine/scenes/tests/city_proof.gd", + "src/game/engine/scenes/tests/city_screen_proof.gd", + "src/game/engine/src/autoloads/event_bus.gd", + "src/game/engine/src/entities/city.gd", + "src/game/engine/src/entities/city_rust_bridge.gd", + "src/game/engine/src/modules/management/turn_processor_helpers.gd", + "src/game/engine/tests/integration/test_1000_turns.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/entities/test_city.gd", + "src/game/engine/tests/unit/test_city_bridge.gd", + "src/game/engine/tests/unit/test_city_screen_p09.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/city/city_buildable_helper.gd", + "line": 178 + }, + { + "file": "src/game/engine/scenes/city/city_buildable_helper.gd", + "line": 262 + }, + { + "file": "src/game/engine/scenes/hud/crafting_complete_modal.gd", + "line": 142 + }, + { + "file": "src/game/engine/scenes/tests/city_proof.gd", + "line": 2 + }, + { + "file": "src/game/engine/scenes/tests/city_proof.gd", + "line": 82 + }, + { + "file": "src/game/engine/scenes/tests/city_proof.gd", + "line": 178 + }, + { + "file": "src/game/engine/scenes/tests/city_screen_proof.gd", + "line": 2 + }, + { + "file": "src/game/engine/src/autoloads/event_bus.gd", + "line": 75 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 1 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 6 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 8 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 88 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 96 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 97 + }, + { + "file": "src/game/engine/src/entities/city.gd", + "line": 424 + }, + { + "file": "src/game/engine/src/entities/city_rust_bridge.gd", + "line": 2 + }, + { + "file": "src/game/engine/src/entities/city_rust_bridge.gd", + "line": 215 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor_helpers.gd", + "line": 95 + }, + { + "file": "src/game/engine/tests/integration/test_1000_turns.gd", + "line": 15 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 56 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 245 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 245 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 249 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 250 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 251 + }, + { + "file": "src/game/engine/tests/unit/entities/test_city.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 2 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 4 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 53 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 55 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 66 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 67 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 121 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 122 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 15 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 16 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 37 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 38 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 57 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 58 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 79 + }, + { + "file": "src/game/engine/tests/unit/test_city_screen_p09.gd", + "line": 80 + } + ] + }, + { + "name": "GdCityActions", + "rustStruct": "GdCityActions", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 4859, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/tests/placement_mode_proof.gd", + "src/game/engine/scenes/world_map/formation_bridge.gd", + "src/game/engine/scenes/world_map/tile_info_panel.gd", + "src/game/engine/scenes/world_map/world_map.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/placement_mode_proof.gd", + "line": 6 + }, + { + "file": "src/game/engine/scenes/tests/placement_mode_proof.gd", + "line": 62 + }, + { + "file": "src/game/engine/scenes/tests/placement_mode_proof.gd", + "line": 63 + }, + { + "file": "src/game/engine/scenes/tests/placement_mode_proof.gd", + "line": 66 + }, + { + "file": "src/game/engine/scenes/tests/placement_mode_proof.gd", + "line": 90 + }, + { + "file": "src/game/engine/scenes/tests/placement_mode_proof.gd", + "line": 93 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 2 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 64 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 68 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 70 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 73 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 75 + }, + { + "file": "src/game/engine/scenes/world_map/tile_info_panel.gd", + "line": 166 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 93 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 1537 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 1554 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 1556 + } + ] + }, + { + "name": "GdClimateEffectsPhysics", + "rustStruct": "GdClimateEffectsPhysics", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 4413, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/climate/climate_effects.gd", + "src/game/engine/src/modules/management/turn_processor.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 481 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 4 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 18 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 26 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 27 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 466 + } + ] + }, + { + "name": "GdClimatePhysics", + "rustStruct": "GdClimatePhysics", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 160, + "funcCount": 2, + "callerFiles": [ + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/climate/climate.gd", + "src/game/engine/src/modules/management/prologue_driver.gd", + "src/game/engine/src/modules/management/turn_processor.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/test_smoke.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 476 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 26 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 72 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 95 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 43 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 461 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 50 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 177 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 178 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 183 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 184 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 185 + }, + { + "file": "src/game/engine/tests/unit/test_smoke.gd", + "line": 47 + }, + { + "file": "src/game/engine/tests/unit/test_smoke.gd", + "line": 50 + } + ] + }, + { + "name": "GdClimateSpecEval", + "rustStruct": "GdClimateSpecEval", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 466, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/src/modules/climate/climate_spec_eval.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/modules/climate/climate_spec_eval.gd", + "line": 4 + }, + { + "file": "src/game/engine/src/modules/climate/climate_spec_eval.gd", + "line": 17 + }, + { + "file": "src/game/engine/src/modules/climate/climate_spec_eval.gd", + "line": 24 + }, + { + "file": "src/game/engine/src/modules/climate/climate_spec_eval.gd", + "line": 34 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 52 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 203 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 204 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 209 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 210 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 211 + } + ] + }, + { + "name": "GdCombatResolver", + "rustStruct": "GdCombatResolver", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 2637, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/combat/combat_preview.gd", + "src/game/engine/scenes/combat/combat_result.gd", + "src/game/engine/scenes/tests/auto_play.gd", + "src/game/engine/scenes/world_map/world_map_combat.gd", + "src/game/engine/src/entities/auto_play.gd", + "src/game/engine/src/entities/combat_utils.gd", + "src/game/engine/src/modules/combat/combat_resolver.gd", + "src/game/engine/src/modules/combat/combat_utils.gd", + "src/game/engine/src/modules/combat/keyword_handler.gd", + "src/game/engine/tests/ffi/test_golden_combat.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/combat/test_combat_bridge.gd", + "src/game/engine/tests/unit/test_combat_resolver.gd", + "src/game/engine/tests/unit/test_keyword_handler.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/combat/combat_preview.gd", + "line": 3 + }, + { + "file": "src/game/engine/scenes/combat/combat_preview.gd", + "line": 14 + }, + { + "file": "src/game/engine/scenes/combat/combat_preview.gd", + "line": 46 + }, + { + "file": "src/game/engine/scenes/combat/combat_preview.gd", + "line": 79 + }, + { + "file": "src/game/engine/scenes/combat/combat_preview.gd", + "line": 188 + }, + { + "file": "src/game/engine/scenes/combat/combat_result.gd", + "line": 3 + }, + { + "file": "src/game/engine/scenes/combat/combat_result.gd", + "line": 54 + }, + { + "file": "src/game/engine/scenes/tests/auto_play.gd", + "line": 2060 + }, + { + "file": "src/game/engine/scenes/tests/auto_play.gd", + "line": 2085 + }, + { + "file": "src/game/engine/scenes/tests/auto_play.gd", + "line": 2086 + }, + { + "file": "src/game/engine/scenes/world_map/world_map_combat.gd", + "line": 103 + }, + { + "file": "src/game/engine/src/entities/auto_play.gd", + "line": 2074 + }, + { + "file": "src/game/engine/src/entities/auto_play.gd", + "line": 2099 + }, + { + "file": "src/game/engine/src/entities/auto_play.gd", + "line": 2100 + }, + { + "file": "src/game/engine/src/entities/combat_utils.gd", + "line": 4 + }, + { + "file": "src/game/engine/src/modules/combat/combat_resolver.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/combat/combat_resolver.gd", + "line": 49 + }, + { + "file": "src/game/engine/src/modules/combat/combat_resolver.gd", + "line": 50 + }, + { + "file": "src/game/engine/src/modules/combat/combat_resolver.gd", + "line": 52 + }, + { + "file": "src/game/engine/src/modules/combat/combat_resolver.gd", + "line": 140 + }, + { + "file": "src/game/engine/src/modules/combat/combat_utils.gd", + "line": 4 + }, + { + "file": "src/game/engine/src/modules/combat/keyword_handler.gd", + "line": 5 + }, + { + "file": "src/game/engine/src/modules/combat/keyword_handler.gd", + "line": 37 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_combat.gd", + "line": 5 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_combat.gd", + "line": 31 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_combat.gd", + "line": 139 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_combat.gd", + "line": 147 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 96 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 308 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 309 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 314 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 315 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 316 + }, + { + "file": "src/game/engine/tests/unit/combat/test_combat_bridge.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/unit/test_combat_resolver.gd", + "line": 10 + }, + { + "file": "src/game/engine/tests/unit/test_combat_resolver.gd", + "line": 11 + }, + { + "file": "src/game/engine/tests/unit/test_combat_resolver.gd", + "line": 28 + }, + { + "file": "src/game/engine/tests/unit/test_combat_resolver.gd", + "line": 38 + }, + { + "file": "src/game/engine/tests/unit/test_keyword_handler.gd", + "line": 5 + } + ] + }, + { + "name": "GdCourierMapView", + "rustStruct": "GdCourierMapView", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3416, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "src/game/engine/tests/unit/test_courier_lifecycle.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 44 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 45 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 106 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 108 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 32 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 33 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 37 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 42 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 43 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 104 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 106 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 9 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 34 + } + ] + }, + { + "name": "GdCourierRoute", + "rustStruct": "GdCourierRoute", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3108, + "funcCount": 9, + "callerFiles": [ + "src/game/engine/tests/unit/test_courier_lifecycle.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 8 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 11 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 148 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 242 + } + ] + }, + { + "name": "GdCulture", + "rustStruct": "GdCulture", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3458, + "funcCount": 7, + "callerFiles": [ + "src/game/engine/src/modules/empire/culture.gd", + "src/game/engine/tests/unit/empire/test_culture_bridge.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/modules/empire/culture.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/empire/culture.gd", + "line": 7 + }, + { + "file": "src/game/engine/src/modules/empire/culture.gd", + "line": 11 + }, + { + "file": "src/game/engine/src/modules/empire/culture.gd", + "line": 15 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 21 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 48 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 49 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 51 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 64 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 65 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 92 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 93 + }, + { + "file": "src/game/engine/tests/unit/empire/test_culture_bridge.gd", + "line": 111 + } + ] + }, + { + "name": "GdCultureWeb", + "rustStruct": "GdCultureWeb", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 4050, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/src/modules/empire/culture_web.gd", + "src/game/engine/src/modules/tech/knowledge_web.gd", + "src/game/engine/tests/unit/test_culture_web.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/modules/empire/culture_web.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/empire/culture_web.gd", + "line": 14 + }, + { + "file": "src/game/engine/src/modules/tech/knowledge_web.gd", + "line": 12 + }, + { + "file": "src/game/engine/tests/unit/test_culture_web.gd", + "line": 2 + }, + { + "file": "src/game/engine/tests/unit/test_culture_web.gd", + "line": 47 + }, + { + "file": "src/game/engine/tests/unit/test_culture_web.gd", + "line": 48 + }, + { + "file": "src/game/engine/tests/unit/test_culture_web.gd", + "line": 50 + }, + { + "file": "src/game/engine/tests/unit/test_culture_web.gd", + "line": 52 + } + ] + }, + { + "name": "GdEcologyPhysics", + "rustStruct": "GdEcologyPhysics", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 202, + "funcCount": 2, + "callerFiles": [ + "src/game/engine/scenes/tests/auto_play.gd", + "src/game/engine/src/entities/auto_play.gd", + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/climate/climate.gd", + "src/game/engine/src/modules/management/prologue_driver.gd", + "src/game/engine/src/modules/management/turn_processor.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/auto_play.gd", + "line": 2676 + }, + { + "file": "src/game/engine/src/entities/auto_play.gd", + "line": 2690 + }, + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 476 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 29 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 98 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 99 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 43 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 461 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 21 + } + ] + }, + { + "name": "GdEconomy", + "rustStruct": "GdEconomy", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3618, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/empire/economy.gd", + "src/game/engine/src/modules/management/turn_processor.gd", + "src/game/engine/tests/unit/empire/test_economy_bridge.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 359 + }, + { + "file": "src/game/engine/src/modules/empire/economy.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/empire/economy.gd", + "line": 8 + }, + { + "file": "src/game/engine/src/modules/empire/economy.gd", + "line": 36 + }, + { + "file": "src/game/engine/src/modules/empire/economy.gd", + "line": 44 + }, + { + "file": "src/game/engine/src/modules/empire/economy.gd", + "line": 47 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 355 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 7 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 44 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 45 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 48 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 62 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 63 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 84 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 99 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 100 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 116 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 126 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 127 + }, + { + "file": "src/game/engine/tests/unit/empire/test_economy_bridge.gd", + "line": 141 + } + ] + }, + { + "name": "GdFaunaEcology", + "rustStruct": "GdFaunaEcology", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 282, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "src/game/engine/src/modules/empire/happiness.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "line": 5 + }, + { + "file": "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "line": 98 + }, + { + "file": "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "line": 99 + }, + { + "file": "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "line": 101 + }, + { + "file": "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "line": 103 + }, + { + "file": "src/game/engine/scenes/tests/proof_biome_economy_coupling.gd", + "line": 125 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 186 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 192 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 213 + } + ] + }, + { + "name": "GdFormationActions", + "rustStruct": "GdFormationActions", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 4982, + "funcCount": 2, + "callerFiles": [], + "callerLines": [] + }, + { + "name": "GdFormationState", + "rustStruct": "GdFormationState", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 5076, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/world_map/formation_bridge.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 2 + } + ] + }, + { + "name": "GdGameState", + "rustStruct": "GdGameState", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 1963, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "src/game/engine/scenes/world_map/formation_bridge.gd", + "src/game/engine/src/entities/player.gd", + "src/game/engine/src/entities/unit.gd", + "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "src/game/engine/tests/integration/test_1000_turns.gd", + "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/test_courier_lifecycle.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 14 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 37 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 38 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 99 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 100 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 24 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 25 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 11 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 35 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 36 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 97 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 98 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 5 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 38 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 83 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 89 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 91 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 168 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 13 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 114 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 116 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 211 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 57 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 104 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 106 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 253 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 15 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 107 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 111 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 164 + }, + { + "file": "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "line": 14 + }, + { + "file": "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "line": 194 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 9 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 12 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 18 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 22 + }, + { + "file": "src/game/engine/src/entities/player.gd", + "line": 183 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 332 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 8 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 10 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 26 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 29 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 46 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 48 + }, + { + "file": "src/game/engine/tests/integration/test_1000_turns.gd", + "line": 21 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 2 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 37 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 40 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 48 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 174 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 175 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 176 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 74 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 282 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 283 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 288 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 289 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 290 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 30 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 33 + } + ] + }, + { + "name": "GdGridState", + "rustStruct": "GdGridState", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 37, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/scenes/city/city_buildable_helper.gd", + "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "src/game/engine/scenes/world_map/tile_info_panel.gd", + "src/game/engine/scenes/world_map/world_map.gd", + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/climate/climate.gd", + "src/game/engine/src/modules/climate/climate_effects.gd", + "src/game/engine/src/modules/climate/weather.gd", + "src/game/engine/src/modules/management/prologue_driver.gd", + "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "src/game/engine/src/modules/management/turn_processor.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/test_climate_tile_sync.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/city/city_buildable_helper.gd", + "line": 103 + }, + { + "file": "src/game/engine/scenes/city/city_buildable_helper.gd", + "line": 104 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 13 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 211 + }, + { + "file": "src/game/engine/scenes/world_map/tile_info_panel.gd", + "line": 124 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 371 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 388 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 390 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 392 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 434 + }, + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 477 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 33 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 82 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 86 + }, + { + "file": "src/game/engine/src/modules/climate/climate.gd", + "line": 133 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 8 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 40 + }, + { + "file": "src/game/engine/src/modules/climate/climate_effects.gd", + "line": 40 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 6 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 47 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 57 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 57 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 106 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 42 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 27 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 37 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 462 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 49 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 166 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 166 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 170 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 171 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 172 + }, + { + "file": "src/game/engine/tests/unit/test_climate_tile_sync.gd", + "line": 6 + } + ] + }, + { + "name": "GdHappiness", + "rustStruct": "GdHappiness", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 719, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/empire/happiness.gd", + "src/game/engine/src/modules/management/turn_processor.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/integration/test_happiness_turn.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 417 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 46 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 47 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 49 + }, + { + "file": "src/game/engine/src/modules/empire/happiness.gd", + "line": 51 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 402 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 55 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 235 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 235 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 239 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 240 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 241 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 4 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 61 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 62 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 126 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 128 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 129 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 324 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 326 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 327 + }, + { + "file": "src/game/engine/tests/integration/test_happiness_turn.gd", + "line": 329 + } + ] + }, + { + "name": "GdItemSystem", + "rustStruct": "GdItemSystem", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 1769, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/src/entities/unit.gd", + "src/game/engine/src/modules/management/item_system.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 94 + }, + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 5 + }, + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 32 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 65 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 269 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 270 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 275 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 276 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 277 + } + ] + }, + { + "name": "GdLootRoller", + "rustStruct": "GdLootRoller", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 1647, + "funcCount": 2, + "callerFiles": [ + "src/game/engine/src/modules/management/item_system.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 7 + }, + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 139 + }, + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 158 + }, + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 181 + }, + { + "file": "src/game/engine/src/modules/management/item_system.gd", + "line": 193 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 64 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 256 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 257 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 262 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 263 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 264 + } + ] + }, + { + "name": "GdMapGenerator", + "rustStruct": "GdMapGenerator", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 407, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 7 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 126 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 128 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 133 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 211 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 51 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 190 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 191 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 196 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 197 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 198 + } + ] + }, + { + "name": "GdMcTreeController", + "rustStruct": "GdMcTreeController", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/ai.rs", + "line": 140, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "src/game/engine/tests/integration/test_ai_simulation.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 6 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 70 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 71 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 72 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "line": 76 + }, + { + "file": "src/game/engine/src/modules/ai/ai_turn_bridge_state.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/integration/test_ai_simulation.gd", + "line": 4 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 98 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 331 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 332 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 337 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 338 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 339 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 6 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 77 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 78 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 94 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 98 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 99 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 107 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 130 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 204 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 205 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 219 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 224 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 237 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 238 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 241 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 277 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 278 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_mcts.gd", + "line": 290 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 89 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 91 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 92 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 124 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 125 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 135 + }, + { + "file": "src/game/engine/tests/unit/ai/test_ai_turn_bridge_stats.gd", + "line": 136 + } + ] + }, + { + "name": "GdOpenBordersAgreement", + "rustStruct": "GdOpenBordersAgreement", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3176, + "funcCount": 6, + "callerFiles": [ + "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "src/game/engine/tests/unit/test_courier_lifecycle.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 120 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 122 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 8 + } + ] + }, + { + "name": "GdPrologue", + "rustStruct": "GdPrologue", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 4525, + "funcCount": 4, + "callerFiles": [ + "src/game/engine/scenes/hud/world_map_hud.gd", + "src/game/engine/scenes/world_map/world_map.gd", + "src/game/engine/src/autoloads/event_bus.gd", + "src/game/engine/src/modules/management/prologue_driver.gd", + "src/game/engine/tests/unit/test_prologue_driver.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/hud/world_map_hud.gd", + "line": 207 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 286 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 371 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 379 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 413 + }, + { + "file": "src/game/engine/scenes/world_map/world_map.gd", + "line": 480 + }, + { + "file": "src/game/engine/src/autoloads/event_bus.gd", + "line": 15 + }, + { + "file": "src/game/engine/src/autoloads/event_bus.gd", + "line": 16 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 10 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 11 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 23 + }, + { + "file": "src/game/engine/src/modules/management/prologue_driver.gd", + "line": 24 + }, + { + "file": "src/game/engine/tests/unit/test_prologue_driver.gd", + "line": 4 + }, + { + "file": "src/game/engine/tests/unit/test_prologue_driver.gd", + "line": 66 + }, + { + "file": "src/game/engine/tests/unit/test_prologue_driver.gd", + "line": 71 + }, + { + "file": "src/game/engine/tests/unit/test_prologue_driver.gd", + "line": 83 + } + ] + }, + { + "name": "GdSharedMapAgreement", + "rustStruct": "GdSharedMapAgreement", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3230, + "funcCount": 8, + "callerFiles": [ + "src/game/engine/tests/unit/test_courier_lifecycle.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 8 + } + ] + }, + { + "name": "GdStockpile", + "rustStruct": "GdStockpile", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 607, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/scenes/city/city_buildable_helper.gd", + "src/game/engine/scenes/tests/items_queue_proof.gd", + "src/game/engine/scenes/tests/treasury_proof.gd", + "src/game/engine/scenes/treasury/treasury_tab.gd", + "src/game/engine/tests/ffi/test_golden_economy.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/test_city_bridge.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/city/city_buildable_helper.gd", + "line": 179 + }, + { + "file": "src/game/engine/scenes/tests/items_queue_proof.gd", + "line": 38 + }, + { + "file": "src/game/engine/scenes/tests/items_queue_proof.gd", + "line": 39 + }, + { + "file": "src/game/engine/scenes/tests/items_queue_proof.gd", + "line": 43 + }, + { + "file": "src/game/engine/scenes/tests/treasury_proof.gd", + "line": 4 + }, + { + "file": "src/game/engine/scenes/tests/treasury_proof.gd", + "line": 54 + }, + { + "file": "src/game/engine/scenes/tests/treasury_proof.gd", + "line": 56 + }, + { + "file": "src/game/engine/scenes/treasury/treasury_tab.gd", + "line": 3 + }, + { + "file": "src/game/engine/scenes/treasury/treasury_tab.gd", + "line": 10 + }, + { + "file": "src/game/engine/scenes/treasury/treasury_tab.gd", + "line": 235 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_economy.gd", + "line": 13 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_economy.gd", + "line": 36 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_economy.gd", + "line": 150 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 53 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 215 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 215 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 219 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 220 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 221 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 69 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 70 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 91 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 124 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 125 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 143 + } + ] + }, + { + "name": "GdTechWeb", + "rustStruct": "GdTechWeb", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3766, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/management/turn_processor.gd", + "src/game/engine/src/modules/management/turn_processor_helpers.gd", + "src/game/engine/src/modules/tech/knowledge_web.gd", + "src/game/engine/src/modules/tech/tech_web.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/management/test_research_bridge.gd", + "src/game/engine/tests/unit/test_tech_web.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 152 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 148 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor_helpers.gd", + "line": 61 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor_helpers.gd", + "line": 71 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor_helpers.gd", + "line": 86 + }, + { + "file": "src/game/engine/src/modules/tech/knowledge_web.gd", + "line": 12 + }, + { + "file": "src/game/engine/src/modules/tech/tech_web.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/tech/tech_web.gd", + "line": 16 + }, + { + "file": "src/game/engine/src/modules/tech/tech_web.gd", + "line": 40 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 29 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 114 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 115 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 360 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 362 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 363 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 2 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 43 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 45 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 71 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 72 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 75 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 83 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 98 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 118 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 136 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 148 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 160 + }, + { + "file": "src/game/engine/tests/unit/management/test_research_bridge.gd", + "line": 184 + }, + { + "file": "src/game/engine/tests/unit/test_tech_web.gd", + "line": 10 + } + ] + }, + { + "name": "GdTrade", + "rustStruct": "GdTrade", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 2822, + "funcCount": 4, + "callerFiles": [ + "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "src/game/engine/src/modules/empire/diplomacy.gd", + "src/game/engine/src/modules/empire/test_diplomacy.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "src/game/engine/tests/unit/test_diplomacy.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 51 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 52 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 111 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 112 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 40 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 41 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 49 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 50 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 109 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 110 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 124 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 143 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 3 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 5 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 14 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 15 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 17 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 19 + }, + { + "file": "src/game/engine/src/modules/empire/test_diplomacy.gd", + "line": 4 + }, + { + "file": "src/game/engine/src/modules/empire/test_diplomacy.gd", + "line": 6 + }, + { + "file": "src/game/engine/src/modules/empire/test_diplomacy.gd", + "line": 172 + }, + { + "file": "src/game/engine/src/modules/empire/test_diplomacy.gd", + "line": 177 + }, + { + "file": "src/game/engine/src/modules/empire/test_diplomacy.gd", + "line": 178 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 97 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 320 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 320 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 324 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 325 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 326 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 7 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 26 + }, + { + "file": "src/game/engine/tests/unit/test_diplomacy.gd", + "line": 4 + }, + { + "file": "src/game/engine/tests/unit/test_diplomacy.gd", + "line": 6 + }, + { + "file": "src/game/engine/tests/unit/test_diplomacy.gd", + "line": 172 + }, + { + "file": "src/game/engine/tests/unit/test_diplomacy.gd", + "line": 177 + }, + { + "file": "src/game/engine/tests/unit/test_diplomacy.gd", + "line": 178 + } + ] + }, + { + "name": "GdTradeLedger", + "rustStruct": "GdTradeLedger", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 3300, + "funcCount": 3, + "callerFiles": [ + "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "src/game/engine/src/autoloads/game_state.gd", + "src/game/engine/src/modules/empire/diplomacy.gd", + "src/game/engine/tests/unit/test_courier_lifecycle.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 21 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 22 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 55 + }, + { + "file": "src/game/engine/scenes/tests/courier_era10_instant_sync_proof.gd", + "line": 116 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 13 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 14 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 55 + }, + { + "file": "src/game/engine/scenes/tests/courier_era2_round_trip_proof.gd", + "line": 56 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 20 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 21 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 54 + }, + { + "file": "src/game/engine/scenes/tests/courier_era7_severance_proof.gd", + "line": 114 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 113 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 114 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 116 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 117 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 140 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 141 + }, + { + "file": "src/game/engine/scenes/tests/diplomacy_courier_proof.gd", + "line": 146 + }, + { + "file": "src/game/engine/src/autoloads/game_state.gd", + "line": 125 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 79 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 81 + }, + { + "file": "src/game/engine/src/modules/empire/diplomacy.gd", + "line": 83 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 7 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 12 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 20 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 22 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 38 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 120 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 141 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 188 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 214 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 234 + }, + { + "file": "src/game/engine/tests/unit/test_courier_lifecycle.gd", + "line": 263 + } + ] + }, + { + "name": "GdTreasury", + "rustStruct": "GdTreasury", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 824, + "funcCount": 4, + "callerFiles": [ + "src/game/engine/scenes/tests/treasury_proof.gd", + "src/game/engine/scenes/treasury/treasury_tab.gd", + "src/game/engine/tests/ffi/test_golden_economy.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd", + "src/game/engine/tests/unit/test_city_bridge.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/treasury_proof.gd", + "line": 3 + }, + { + "file": "src/game/engine/scenes/tests/treasury_proof.gd", + "line": 42 + }, + { + "file": "src/game/engine/scenes/tests/treasury_proof.gd", + "line": 44 + }, + { + "file": "src/game/engine/scenes/treasury/treasury_tab.gd", + "line": 3 + }, + { + "file": "src/game/engine/scenes/treasury/treasury_tab.gd", + "line": 10 + }, + { + "file": "src/game/engine/scenes/treasury/treasury_tab.gd", + "line": 214 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_economy.gd", + "line": 14 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_economy.gd", + "line": 37 + }, + { + "file": "src/game/engine/tests/ffi/test_golden_economy.gd", + "line": 150 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 54 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 225 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 225 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 229 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 230 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 231 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 72 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 73 + }, + { + "file": "src/game/engine/tests/unit/test_city_bridge.gd", + "line": 103 + } + ] + }, + { + "name": "GdTurnProcessor", + "rustStruct": "GdTurnProcessor", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 2403, + "funcCount": 2, + "callerFiles": [ + "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "src/game/engine/scenes/tests/iter_7j_encounters_only_proof.gd", + "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "src/game/engine/scenes/tests/iter_7l_per_lair_tier_proof.gd", + "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "src/game/engine/src/modules/management/rust_fauna_integration.gd", + "src/game/engine/src/modules/management/turn_processor_signals.gd", + "src/game/engine/tests/integration/test_1000_turns.gd", + "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "src/game/engine/tests/integration/test_gdextension_contract.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 2 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 6 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 38 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 68 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 83 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 84 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 86 + }, + { + "file": "src/game/engine/scenes/tests/iter_7e_turn_bridge_proof.gd", + "line": 168 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 2 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 17 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 89 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 109 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 111 + }, + { + "file": "src/game/engine/scenes/tests/iter_7g_real_mapgen_proof.gd", + "line": 211 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 57 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 99 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 101 + }, + { + "file": "src/game/engine/scenes/tests/iter_7h_dict_adapter_proof.gd", + "line": 253 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 6 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 60 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 101 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 103 + }, + { + "file": "src/game/engine/scenes/tests/iter_7i_unit_adapter_proof.gd", + "line": 222 + }, + { + "file": "src/game/engine/scenes/tests/iter_7j_encounters_only_proof.gd", + "line": 15 + }, + { + "file": "src/game/engine/scenes/tests/iter_7j_encounters_only_proof.gd", + "line": 54 + }, + { + "file": "src/game/engine/scenes/tests/iter_7j_encounters_only_proof.gd", + "line": 95 + }, + { + "file": "src/game/engine/scenes/tests/iter_7j_encounters_only_proof.gd", + "line": 97 + }, + { + "file": "src/game/engine/scenes/tests/iter_7j_encounters_only_proof.gd", + "line": 197 + }, + { + "file": "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "line": 16 + }, + { + "file": "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "line": 104 + }, + { + "file": "src/game/engine/scenes/tests/iter_7k_turn_processor_gated_proof.gd", + "line": 231 + }, + { + "file": "src/game/engine/scenes/tests/iter_7l_per_lair_tier_proof.gd", + "line": 188 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 11 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "line": 29 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_integration.gd", + "line": 11 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_integration.gd", + "line": 42 + }, + { + "file": "src/game/engine/src/modules/management/rust_fauna_integration.gd", + "line": 45 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor_signals.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/integration/test_1000_turns.gd", + "line": 5 + }, + { + "file": "src/game/engine/tests/integration/test_1000_turns.gd", + "line": 21 + }, + { + "file": "src/game/engine/tests/integration/test_1000_turns.gd", + "line": 29 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 2 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 10 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 37 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 39 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 44 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 127 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 135 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 164 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 166 + }, + { + "file": "src/game/engine/tests/integration/test_gd_turn_processor.gd", + "line": 167 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 89 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 295 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 296 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 301 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 302 + }, + { + "file": "src/game/engine/tests/integration/test_gdextension_contract.gd", + "line": 303 + } + ] + }, + { + "name": "GdUnitActions", + "rustStruct": "GdUnitActions", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/action.rs", + "line": 14, + "funcCount": 1, + "callerFiles": [ + "src/game/engine/scenes/hud/unit_panel.gd", + "src/game/engine/scenes/world_map/formation_bridge.gd", + "src/game/engine/src/entities/unit.gd", + "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "src/game/engine/tests/unit/test_patrol.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/scenes/hud/unit_panel.gd", + "line": 5 + }, + { + "file": "src/game/engine/scenes/hud/unit_panel.gd", + "line": 169 + }, + { + "file": "src/game/engine/scenes/hud/unit_panel.gd", + "line": 170 + }, + { + "file": "src/game/engine/scenes/hud/unit_panel.gd", + "line": 259 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 82 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 84 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 87 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 89 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 96 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 97 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 99 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 107 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 109 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 112 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 120 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 121 + }, + { + "file": "src/game/engine/scenes/world_map/formation_bridge.gd", + "line": 123 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 272 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 277 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 280 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 282 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 293 + }, + { + "file": "src/game/engine/src/entities/unit.gd", + "line": 295 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 3 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 119 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 123 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 124 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 126 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 137 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 138 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 140 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 149 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 150 + }, + { + "file": "src/game/engine/tests/unit/entities/test_unit_actions.gd", + "line": 152 + }, + { + "file": "src/game/engine/tests/unit/test_patrol.gd", + "line": 6 + } + ] + }, + { + "name": "GdWeatherPhysics", + "rustStruct": "GdWeatherPhysics", + "base": "RefCounted", + "file": "src/simulator/api-gdext/src/lib.rs", + "line": 4340, + "funcCount": 2, + "callerFiles": [ + "src/game/engine/src/entities/turn_processor.gd", + "src/game/engine/src/modules/climate/weather.gd", + "src/game/engine/src/modules/management/turn_processor.gd" + ], + "callerLines": [ + { + "file": "src/game/engine/src/entities/turn_processor.gd", + "line": 479 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 4 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 22 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 24 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 35 + }, + { + "file": "src/game/engine/src/modules/climate/weather.gd", + "line": 37 + }, + { + "file": "src/game/engine/src/modules/management/turn_processor.gd", + "line": 464 + } + ] + } + ], + "gdClassNames": { + "AchievementTracker": "src/game/engine/src/modules/management/achievement_tracker.gd", + "AiTurnBridge": "src/game/engine/src/modules/ai/ai_turn_bridge.gd", + "AiTurnOverlay": "src/game/engine/scenes/hud/ai_turn_overlay.gd", + "AirFaunaModel": "src/game/engine/src/models/world/air_fauna.gd", + "AnchorDecay": "src/game/engine/src/modules/climate/anchor_decay.gd", + "Archon": "src/game/engine/src/entities/archon.gd", + "ArenaOverlay": "src/game/engine/scenes/world_map/arena_overlay.gd", + "AscensionRitual": "src/game/engine/src/modules/victory/ascension_ritual.gd", + "Atmosphere": "src/game/engine/src/modules/climate/atmosphere.gd", + "AtmosphereAnomalies": "src/game/engine/src/modules/climate/atmosphere_anomalies.gd", + "AudioLoader": "src/game/engine/src/audio/audio_loader.gd", + "AudioResolver": "src/game/engine/src/audio/audio_resolver.gd", + "BiomeClassifier": "src/game/engine/src/models/world/biome_classifier.gd", + "BiomeModel": "src/game/engine/src/models/world/biome.gd", + "Building": "src/game/engine/src/entities/building.gd", + "ChroniclePanel": "src/game/engine/scenes/hud/chronicle_panel.gd", + "City": "src/game/engine/src/entities/city.gd", + "CityDetailFormatter": "src/game/engine/scenes/city/city_detail_formatter.gd", + "CityRenderer": "src/game/engine/src/rendering/city_renderer.gd", + "CitySiteScorer": "src/game/engine/src/modules/management/city_site_scorer.gd", + "Climate": "src/game/engine/src/modules/climate/climate.gd", + "ClimateEffects": "src/game/engine/src/modules/climate/climate_effects.gd", + "ClimateSpecEval": "src/game/engine/src/modules/climate/climate_spec_eval.gd", + "CombatResolver": "src/game/engine/src/modules/combat/combat_resolver.gd", + "CombatUtils": "src/game/engine/src/modules/combat/combat_utils.gd", + "CourierRouteOverlay": "src/game/engine/scenes/world_map/courier_route_overlay.gd", + "Culture": "src/game/engine/src/modules/empire/culture.gd", + "CultureTree": "src/game/engine/scenes/culture_tree/culture_tree.gd", + "CultureWeb": "src/game/engine/src/modules/empire/culture_web.gd", + "Diplomacy": "src/game/engine/src/modules/empire/diplomacy.gd", + "EcologicalEvents": "src/game/engine/src/modules/climate/ecological_events.gd", + "EcologyDB": "src/game/engine/src/modules/ecology/ecology_db.gd", + "EcologyInitializer": "src/game/engine/src/modules/ecology/ecology_initializer.gd", + "Economy": "src/game/engine/src/modules/empire/economy.gd", + "EcosystemSimplified": "src/game/engine/src/modules/ecology/ecosystem_simplified.gd", + "EntityFinder": "src/game/engine/src/map/entity_finder.gd", + "FaunaDynamics": "src/game/engine/src/modules/ecology/fauna.gd", + "FaunaSimplified": "src/game/engine/src/modules/ecology/fauna_simplified.gd", + "FlavorGenerator": "src/game/engine/src/models/world/flavor_generator.gd", + "FloatingViewportWindow": "src/game/engine/src/ui/floating_viewport_window.gd", + "FloraProfile": "src/game/engine/src/models/world/flora_profile.gd", + "FoodWebRules": "src/game/engine/src/models/world/food_web_rules.gd", + "GameMap": "src/game/engine/src/map/game_map.gd", + "GoldenVectorLoader": "src/game/engine/tests/ffi/golden_vector_loader.gd", + "Government": "src/game/engine/src/modules/empire/government.gd", + "GutErrorTracker": "src/game/addons/gut/error_tracker.gd", + "GutHookScript": "src/game/addons/gut/hook_script.gd", + "GutInputFactory": "src/game/addons/gut/input_factory.gd", + "GutInputSender": "src/game/addons/gut/input_sender.gd", + "GutMain": "src/game/addons/gut/gut.gd", + "GutStringUtils": "src/game/addons/gut/strutils.gd", + "GutTest": "src/game/addons/gut/test.gd", + "GutTrackedError": "src/game/addons/gut/gut_tracked_error.gd", + "GutUtils": "src/game/addons/gut/utils.gd", + "Happiness": "src/game/engine/src/modules/empire/happiness.gd", + "HappinessBreakdownPanel": "src/game/engine/scenes/hud/happiness_breakdown_panel.gd", + "HexRenderer": "src/game/engine/src/rendering/hex_renderer.gd", + "HexUtils": "src/game/engine/src/map/hex_utils.gd", + "HotkeySheet": "src/game/engine/scenes/hud/hotkey_sheet.gd", + "Hydrology": "src/game/engine/src/generation/hydrology.gd", + "HydrologyRivers": "src/game/engine/src/generation/hydrology_rivers.gd", + "Improvement": "src/game/engine/src/entities/improvement.gd", + "ImprovementManager": "src/game/engine/src/modules/management/improvement_manager.gd", + "IndicatorRenderer": "src/game/engine/src/rendering/indicator_renderer.gd", + "ItemSystem": "src/game/engine/src/modules/management/item_system.gd", + "KeywordHandler": "src/game/engine/src/modules/combat/keyword_handler.gd", + "KnowledgeTree": "src/game/engine/scenes/knowledge_tree/knowledge_tree.gd", + "KnowledgeWeb": "src/game/engine/src/modules/tech/knowledge_web.gd", + "LairOverlayRenderer": "src/game/engine/src/rendering/lair_overlay_renderer.gd", + "LandFaunaModel": "src/game/engine/src/models/world/land_fauna.gd", + "LeyNetwork": "src/game/engine/src/modules/ley/ley_network.gd", + "LeyResidue": "src/game/engine/src/modules/ley/ley_residue.gd", + "MapGenerator": "src/game/engine/src/generation/map_generator.gd", + "MapLoader": "src/game/engine/src/map/map_loader.gd", + "MapPlacer": "src/game/engine/src/generation/map_placer.gd", + "MapShapeSeeds": "src/game/engine/src/generation/map_shape_seeds.gd", + "MarineFaunaModel": "src/game/engine/src/models/world/marine_fauna.gd", + "MarineHarvest": "src/game/engine/src/modules/events/marine_harvest.gd", + "NaturalEvents": "src/game/engine/src/modules/events/natural_events.gd", + "NaturalEventsConditions": "src/game/engine/src/modules/events/natural_events_conditions.gd", + "NaturalEventsEffects": "src/game/engine/src/modules/events/natural_events_effects.gd", + "OverlayRenderer": "src/game/engine/src/rendering/overlay_renderer.gd", + "Pathfinder": "src/game/engine/src/map/pathfinder.gd", + "PendingActions": "src/game/engine/src/core/pending_actions.gd", + "PersonalityAssigner": "src/game/engine/src/modules/ai/personality_assigner.gd", + "Player": "src/game/engine/src/entities/player.gd", + "ProductionFilter": "src/game/engine/src/modules/management/production_filter.gd", + "PrologueDriver": "src/game/engine/src/modules/management/prologue_driver.gd", + "PrologueOverlayRenderer": "src/game/engine/src/rendering/prologue_overlay_renderer.gd", + "RiverRenderer": "src/game/engine/src/rendering/river_renderer.gd", + "RoadRenderer": "src/game/engine/src/rendering/road_renderer.gd", + "RustFaunaBridge": "src/game/engine/src/modules/management/rust_fauna_bridge.gd", + "RustFaunaIntegration": "src/game/engine/src/modules/management/rust_fauna_integration.gd", + "SaveManager": "src/game/engine/src/core/save_manager.gd", + "SpeciesGenerator": "src/game/engine/src/models/world/species_generator.gd", + "SpellSystem": "src/game/engine/src/modules/magic/spell_system.gd", + "SplitPanelContainer": "src/game/engine/src/ui/split_panel_container.gd", + "StartBalancer": "src/game/engine/src/generation/start_balancer.gd", + "StartPosition": "src/game/engine/src/generation/start_position.gd", + "SubstrateType": "src/game/engine/src/models/world/substrate.gd", + "TechTree": "src/game/engine/scenes/tech_tree/tech_tree.gd", + "TechWeb": "src/game/engine/src/modules/tech/tech_web.gd", + "TerrainAffinity": "src/game/engine/src/core/terrain_affinity.gd", + "TerrainRefiner": "src/game/engine/src/generation/terrain_refiner.gd", + "Tile": "src/game/engine/src/map/tile.gd", + "TileSerializer": "src/game/engine/src/map/tile_serializer.gd", + "TraitSet": "src/game/engine/src/models/world/species_traits.gd", + "TurnNotification": "src/game/engine/scenes/hud/turn_notification.gd", + "TutorialOverlay": "src/game/engine/scenes/hud/tutorial_overlay.gd", + "Unit": "src/game/engine/src/entities/unit.gd", + "UnitManager": "src/game/engine/src/modules/management/unit_manager.gd", + "UnitRenderer": "src/game/engine/src/rendering/unit_renderer.gd", + "UnitStatHelpers": "src/game/engine/src/entities/unit_stat_helpers.gd", + "VictoryManager": "src/game/engine/src/modules/victory/victory_manager.gd", + "ViewportPanel": "src/game/engine/src/ui/viewport_panel.gd", + "ViewportWindowManager": "src/game/engine/src/ui/viewport_window_manager.gd", + "VillageLairPlacer": "src/game/engine/src/generation/village_lair_placer.gd", + "WaterBody": "src/game/engine/src/models/world/water_body.gd", + "WaterBodyFinder": "src/game/engine/src/modules/ecology/water_body_finder.gd", + "Weather": "src/game/engine/src/modules/climate/weather.gd", + "WeatherEvents": "src/game/engine/src/modules/climate/weather_events.gd", + "WildCreatureAI": "src/game/engine/src/modules/ai/wild_creature_ai.gd", + "WindCalculator": "src/game/engine/src/generation/wind_calculator.gd", + "WorldMapHover": "src/game/engine/scenes/world_map/world_map_hover.gd", + "WorldMapHud": "src/game/engine/scenes/hud/world_map_hud.gd" + }, + "collisions": [], + "crateDeps": { + "magic-civ-physics": [ + "mc-climate", + "mc-compute", + "mc-core", + "mc-mapgen" + ], + "magic-civ-physics-gdext": [ + "mc-ai", + "mc-city", + "mc-climate", + "mc-combat", + "mc-compute", + "mc-core", + "mc-culture", + "mc-ecology", + "mc-economy", + "mc-happiness", + "mc-items", + "mc-mapgen", + "mc-mcts-service", + "mc-tech", + "mc-trade", + "mc-turn" + ], + "mc-ai": [ + "mc-combat", + "mc-core", + "mc-trade" + ], + "mc-balance": [ + "mc-ai" + ], + "mc-city": [ + "mc-core", + "mc-economy" + ], + "mc-climate": [ + "mc-core" + ], + "mc-combat": [ + "mc-core" + ], + "mc-compute": [ + "mc-climate", + "mc-core" + ], + "mc-core": [], + "mc-culture": [ + "mc-core", + "mc-tech" + ], + "mc-ecology": [ + "mc-climate", + "mc-compute", + "mc-core", + "mc-flora" + ], + "mc-economy": [ + "mc-core" + ], + "mc-flora": [ + "mc-core" + ], + "mc-happiness": [ + "mc-core" + ], + "mc-items": [], + "mc-magic": [ + "mc-core" + ], + "mc-mapgen": [ + "mc-core", + "mc-turn" + ], + "mc-mcts-service": [ + "mc-ai", + "mc-turn" + ], + "mc-observation": [ + "mc-core" + ], + "mc-replay": [], + "mc-sim": [ + "mc-ai", + "mc-balance", + "mc-city", + "mc-climate", + "mc-combat", + "mc-compute", + "mc-core", + "mc-culture", + "mc-ecology", + "mc-economy", + "mc-flora", + "mc-mapgen", + "mc-turn" + ], + "mc-tech": [ + "mc-core" + ], + "mc-trade": [], + "mc-turn": [ + "mc-ai", + "mc-city", + "mc-combat", + "mc-core", + "mc-culture", + "mc-economy", + "mc-happiness", + "mc-tech", + "mc-trade" + ] + } +} \ No newline at end of file diff --git a/public/games/age-of-dwarves/docs/HEX_GEOMETRY.md b/public/games/age-of-dwarves/docs/HEX_GEOMETRY.md index a4b88282..0d7a1302 100644 --- a/public/games/age-of-dwarves/docs/HEX_GEOMETRY.md +++ b/public/games/age-of-dwarves/docs/HEX_GEOMETRY.md @@ -226,6 +226,7 @@ The model in this doc is the **target** spec; the code is partial. | Pathfinding (Rust A*) | (does not yet exist in Rust) | ⚠️ No Rust A* found in `mc-core/src/algorithms/`; existing pathfinding lives GDScript-side. `validate_centre_to_centre_move` is ready for the future Rust pathfinder to call. | | Renderer | `src/packages/guide/src/components/climate-sim/HexGLRenderer.tsx` | ✅ Hex tile rendering correct; no inner-hex / edge-slot overlay (debug-only feature pending) | | AI evaluator | `src/simulator/crates/mc-ai/src/evaluator.rs:414-480` | ⚠️ Scores formations by size + threat; does not yet model edge-slot positioning | +| GDExtension bridge | `src/simulator/api-gdext/src/lib.rs::GdGameState::engagement_interceptor / validate_centre_to_centre_move` | ✅ Two Godot-callable primitives expose the edge model to GDScript. Combat preview UI consults `engagement_interceptor`; movement preview consults `validate_centre_to_centre_move` and branches on `reason` (`not_adjacent / wall_blocks / edge_occupied / adjacent_clean`). | **Test coverage** (`cargo test -p mc-core --lib`): 70 tests (was 30 before this work) covering edge identity, passability, move validation, engagement interception, ZOC reach (centre + edge), formation slot model, blend-table lookup with production-JSON round-trip, cross-file schema guard (every blend → defined terrain), river-edges migration. `cargo test -p mc-mapgen --lib`: 24 tests including 3 river-determinism guards. diff --git a/public/games/age-of-dwarves/manifest.json b/public/games/age-of-dwarves/manifest.json index f60df656..0f235a74 100644 --- a/public/games/age-of-dwarves/manifest.json +++ b/public/games/age-of-dwarves/manifest.json @@ -62,18 +62,15 @@ "dwarf_grand_scout", "dwarf_grand_smith", "dwarf_graven_warrior", - "dwarf_gyrocopter", "dwarf_hammerguard", "dwarf_high_engineer", "dwarf_high_sapper", "dwarf_high_smith", - "dwarf_iron_hawk", "dwarf_iron_submarine", "dwarf_iron_vanguard", "dwarf_ironwarden", "dwarf_master_woodcutter", "dwarf_mithril_cruiser", - "dwarf_mithril_hawk", "dwarf_mithril_vanguard", "dwarf_prospector", "dwarf_repeating_arbalest", diff --git a/public/resources/buildings/airfield.json b/public/resources/buildings/airfield.json index 4429fdeb..ddf167de 100644 --- a/public/resources/buildings/airfield.json +++ b/public/resources/buildings/airfield.json @@ -1,7 +1,7 @@ { "id": "airfield", - "name": "Airfield", - "description": "A flat expanse carved from the mountainside with launch rails and landing strips. Required for all air unit production.", + "name": "Airship Yard", + "description": "Mooring masts, gas-bag bays, and a small steam-pumping station. The first dwarven foothold in the air — built to assemble and launch armored airships. Fixed-wing flight remains beyond Game-1 dwarven engineering.", "placement": "city", "category": "military", "school": null, @@ -32,8 +32,6 @@ ] }, "produces": [ - "dwarf_gyrocopter", - "dwarf_iron_hawk", "dwarf_steam_bomber" ], "stack_mode": "parallel" diff --git a/public/resources/buildings/tank_yard.json b/public/resources/buildings/tank_yard.json index d168e99d..21170daa 100644 --- a/public/resources/buildings/tank_yard.json +++ b/public/resources/buildings/tank_yard.json @@ -39,7 +39,7 @@ "strike_walker" ], "stack_mode": "parallel", - "requires_existing": "walker_yard", + "requires_existing": null, "consumes_existing": false } ] diff --git a/public/resources/buildings/walker_yard.json b/public/resources/buildings/walker_yard.json index c63857b9..a7d82627 100644 --- a/public/resources/buildings/walker_yard.json +++ b/public/resources/buildings/walker_yard.json @@ -38,6 +38,7 @@ "iron_sentinel", "dwarf_steam_golem" ], - "stack_mode": "parallel" + "stack_mode": "parallel", + "requires_existing": "tank_yard" } ] diff --git a/public/resources/buildings/zeppelin_dock.json b/public/resources/buildings/zeppelin_dock.json index 19274480..714eb2a4 100644 --- a/public/resources/buildings/zeppelin_dock.json +++ b/public/resources/buildings/zeppelin_dock.json @@ -34,7 +34,6 @@ }, "produces": [ "dwarf_war_zeppelin", - "dwarf_mithril_hawk", "dwarf_sky_fortress" ], "stack_mode": "parallel", diff --git a/src/game/engine/tests/unit/test_victory_manager.gd b/src/game/engine/tests/unit/test_victory_manager.gd index 7c84f66a..2fd01470 100644 --- a/src/game/engine/tests/unit/test_victory_manager.gd +++ b/src/game/engine/tests/unit/test_victory_manager.gd @@ -1,26 +1,84 @@ extends GutTest -## VictoryManager unit tests — PENDING until VictoryManager is implemented. +## VictoryManager — elimination reconciliation pass (p2-45). ## -## `src/game/engine/src/modules/victory/victory_manager.gd` is a -## 2-line stub (`class_name VictoryManager extends RefCounted`). -## None of the methods the original tests exercised (`get_score`, -## `get_scores`, `check_victory`) and none of the score constants -## (`SCORE_CITY`, `SCORE_POP`, `SCORE_TECH`, `SCORE_UNIT`) exist. +## `victory_manager._reconcile_eliminations` fires +## `EventBus.player_eliminated` exactly once per player whose +## (cities ∪ living-founder) set transitions to empty. The +## `is_eliminated` latch on PlayerScript dedupes against the existing +## combat-utils emit so per-turn sweeps don't double-fire. ## -## There is also no Rust-side bridge — `mc-turn::victory` or a -## `GdVictoryManager` extension has not been authored yet. -## Reported to team-lead for iter 7n+. -## -## The original tests also referenced Player/City/Unit fields that -## were dropped in iter 7i/7l (`is_player_controlled`, `city_name`, -## `population`, `owned_tiles`, `type_id`, `id`). Rehydrating these -## tests will require re-authoring both sides against the current -## entity API. +## (The earlier stub of this file pre-dates the VictoryManager port — +## the manager has been real since iter 7n. Rehydrated here for p2-45.) + +const VictoryManagerScript: GDScript = preload("res://engine/src/modules/victory/victory_manager.gd") +const PlayerScript: GDScript = preload("res://engine/src/entities/player.gd") -func test_victory_manager_pending() -> void: - pending( - "VictoryManager is a 2-line stub in iter 7n — see" - + " src/game/engine/src/modules/victory/victory_manager.gd." - + " No methods to exercise yet; rehydrate when implemented." - ) +func before_all() -> void: + DataLoader.load_theme("age-of-dwarves") + + +func before_each() -> void: + GameState.players.clear() + var human: RefCounted = PlayerScript.new() + human.player_name = "Player" + human.is_human = true + human.index = 0 + # Survivor: keeps a phantom city Dictionary so cities.size() > 0. + human.cities = [{"display_name": "Khazad-dum"}] + GameState.players.append(human) + var ai: RefCounted = PlayerScript.new() + ai.player_name = "Rival" + ai.is_human = false + ai.index = 1 + # Eliminated: no cities, no founder. Reconciliation should fire on first sweep. + ai.cities = [] + ai.units = [] + GameState.players.append(ai) + GameState.current_player_index = 0 + + +func _capture_eliminations() -> Array[int]: + var captured: Array[int] = [] + var handler: Callable = func(idx: int) -> void: captured.append(idx) + EventBus.player_eliminated.connect(handler) + var vm: RefCounted = VictoryManagerScript.new() + vm.call("_reconcile_eliminations") + EventBus.player_eliminated.disconnect(handler) + return captured + + +func test_reconciliation_emits_for_eliminated_player() -> void: + var captured: Array[int] = _capture_eliminations() + assert_eq(captured.size(), 1, "AI with no cities + no founder must trigger one emit") + assert_eq(captured[0], 1, "the eliminated player's index must be the rival (1)") + + +func test_reconciliation_latches_is_eliminated_flag() -> void: + var ai: PlayerScript = GameState.players[1] as PlayerScript + assert_false(ai.is_eliminated, "starts un-latched") + _capture_eliminations() + assert_true(ai.is_eliminated, "first sweep latches is_eliminated to true") + + +func test_second_sweep_is_silent() -> void: + # First sweep emits and latches; a second sweep on the same turn must + # NOT re-emit. This is the dedupe contract. + _capture_eliminations() + var second: Array[int] = _capture_eliminations() + assert_eq(second.size(), 0, "second reconciliation sweep must not re-emit") + + +func test_survivor_does_not_trigger() -> void: + var captured: Array[int] = _capture_eliminations() + for idx: int in captured: + assert_ne(idx, 0, "the human (still has a city) must NOT be in the eliminated set") + + +func test_already_eliminated_flag_skips_emit() -> void: + # Simulates combat_utils having already announced the elimination — + # reconciliation must respect the latch and stay silent. + var ai: PlayerScript = GameState.players[1] as PlayerScript + ai.is_eliminated = true + var captured: Array[int] = _capture_eliminations() + assert_eq(captured.size(), 0, "reconciliation must not re-emit when is_eliminated already true") diff --git a/src/simulator/api-gdext/src/lib.rs b/src/simulator/api-gdext/src/lib.rs index 479c8c06..b3ff738e 100644 --- a/src/simulator/api-gdext/src/lib.rs +++ b/src/simulator/api-gdext/src/lib.rs @@ -2387,6 +2387,106 @@ impl GdGameState { } arr } + + // ── Edge slot bridge (HEX_GEOMETRY.md §5, §7) ───────────────────────── + // + // Three Godot-callable primitives exposing the centre + 6 edge slots + // model to GDScript: combat preview asks "is there an interceptor on + // the edge?", movement preview asks "can this unit cross the edge?". + + /// Look up the edge interceptor between two adjacent hex centres. + /// + /// Returns a Dictionary: + /// - `has_interceptor`: bool + /// - `unit_id`: int (only valid when has_interceptor) + /// - `owner_player_id`: int (only valid when has_interceptor) + /// - `aligned_to`: Vector2i (parent hex of the interceptor, only valid when present) + /// + /// Returns `has_interceptor: false` for non-adjacent hexes or vacant edges. + /// Per `HEX_GEOMETRY.md` §5, an edge unit is hit before the defender's + /// centre — combat preview UIs must surface this to the player. + #[func] + pub fn engagement_interceptor( + &self, + atk_q: i64, + atk_r: i64, + def_q: i64, + def_r: i64, + ) -> Dictionary { + let mut d = Dictionary::new(); + let interceptor = self.inner.grid.as_ref().and_then(|g| { + g.engagement_interceptor((atk_q as i32, atk_r as i32), (def_q as i32, def_r as i32)) + }); + match interceptor { + Some(occ) => { + d.set("has_interceptor", true); + d.set("unit_id", occ.unit_id as i64); + d.set("owner_player_id", occ.owner_player_id as i64); + d.set( + "aligned_to", + Vector2i::new(occ.aligned_to.0, occ.aligned_to.1), + ); + } + None => { + d.set("has_interceptor", false); + } + } + d + } + + /// Validate a single-step centre-to-centre move for `player_id`. + /// + /// Returns a Dictionary: + /// - `ok`: bool + /// - `reason`: String — one of `"adjacent_clean"` (when ok=true), + /// `"not_adjacent"`, `"wall_blocks"`, `"edge_occupied"` (when ok=false) + /// + /// Movement preview UIs branch on `reason` to show the appropriate + /// player feedback (greyed path, wall icon, enemy unit at edge). + #[func] + pub fn validate_centre_to_centre_move( + &self, + from_q: i64, + from_r: i64, + to_q: i64, + to_r: i64, + player_id: i64, + ) -> Dictionary { + use mc_core::grid::MoveBlockedReason; + let mut d = Dictionary::new(); + let result = self.inner.grid.as_ref().map(|g| { + g.validate_centre_to_centre_move( + (from_q as i32, from_r as i32), + (to_q as i32, to_r as i32), + player_id as u32, + ) + }); + match result { + Some(Ok(_edge)) => { + d.set("ok", true); + d.set("reason", GString::from("adjacent_clean")); + } + Some(Err(MoveBlockedReason::NotAdjacent)) => { + d.set("ok", false); + d.set("reason", GString::from("not_adjacent")); + } + Some(Err(MoveBlockedReason::WallBlocks)) => { + d.set("ok", false); + d.set("reason", GString::from("wall_blocks")); + } + Some(Err(MoveBlockedReason::EdgeOccupied)) => { + d.set("ok", false); + d.set("reason", GString::from("edge_occupied")); + } + None => { + // No grid loaded — treat as not-adjacent fallback so UI + // doesn't try to draw a movement preview. + d.set("ok", false); + d.set("reason", GString::from("no_grid")); + } + } + d + } } // ── GdTurnProcessor ───────────────────────────────────────────────────── diff --git a/tools/gd-rust-relationships.py b/tools/gd-rust-relationships.py index ef9ddbc5..aad55da0 100755 --- a/tools/gd-rust-relationships.py +++ b/tools/gd-rust-relationships.py @@ -201,6 +201,43 @@ def parse_crate_deps(sim_root: Path) -> dict[str, set[str]]: return deps +def build_json( + classes: list[RustClass], + gd_classes: dict[str, Path], + deps: dict[str, set[str]], +) -> dict: + rust_names = {c.name for c in classes} + return { + "generatedAt": __import__("datetime").datetime.utcnow().isoformat() + "Z", + "classes": [ + { + "name": c.name, + "rustStruct": c.rust_struct, + "base": c.base, + "file": str(c.file.relative_to(REPO_ROOT)), + "line": c.line, + "funcCount": c.func_count, + "callerFiles": sorted( + {str(p.relative_to(REPO_ROOT)) for p, _ in c.callers} + ), + "callerLines": [ + {"file": str(p.relative_to(REPO_ROOT)), "line": ln} + for p, ln in sorted(c.callers, key=lambda x: (str(x[0]), x[1])) + ], + } + for c in sorted(classes, key=lambda x: x.name) + ], + "gdClassNames": { + name: str(path.relative_to(REPO_ROOT)) + for name, path in sorted(gd_classes.items()) + }, + "collisions": sorted(set(gd_classes) & rust_names), + "crateDeps": { + crate: sorted(ds) for crate, ds in sorted(deps.items()) + }, + } + + def render_report( classes: list[RustClass], gd_classes: dict[str, Path], @@ -296,6 +333,8 @@ def render_report( def main() -> int: + import json + ap = argparse.ArgumentParser() ap.add_argument( "--out", @@ -303,6 +342,7 @@ def main() -> int: default=REPO_ROOT / ".project" / "reports" / "gd-rust-relationships.md", ) args = ap.parse_args() + json_out = args.out.with_suffix(".json") if not GDEXT_SRC.is_dir(): print(f"error: {GDEXT_SRC} not found", file=sys.stderr) @@ -314,9 +354,11 @@ def main() -> int: gd_classes = parse_gd_class_names(gd_files) deps = parse_crate_deps(SIM_ROOT) - report = render_report(classes, gd_classes, deps) args.out.parent.mkdir(parents=True, exist_ok=True) - args.out.write_text(report, encoding="utf-8") + args.out.write_text(render_report(classes, gd_classes, deps), encoding="utf-8") + json_out.write_text( + json.dumps(build_json(classes, gd_classes, deps), indent=2), encoding="utf-8" + ) referenced = sum(1 for c in classes if c.callers) print( @@ -324,7 +366,7 @@ def main() -> int: f"{len(list(GDEXT_SRC.rglob('*.rs')))} api-gdext files; " f"{referenced} referenced from {len(gd_files)} .gd files. " f"Crates: {len(deps)}. " - f"Report: {args.out.relative_to(REPO_ROOT)}" + f"Markdown: {args.out.relative_to(REPO_ROOT)} JSON: {json_out.relative_to(REPO_ROOT)}" ) return 0