Ground widened add-building descriptor names
This commit is contained in:
parent
b2da02befa
commit
a3df447186
6 changed files with 287 additions and 15 deletions
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"binding_catalog_version": 1,
|
||||
"notes": [
|
||||
"Add-building descriptor ids 503..613 now ground candidate id as descriptor_id - 503 through direct disassembly of 0x00430270 world_try_place_random_structure_batch_from_compact_record.",
|
||||
"The concrete candidate names below are checked against the stable RT3 1.05 candidate-availability table order exposed by runtime inspect-candidate-table on Alternate USA, Southern Pacific, and Spanish Mainline saves.",
|
||||
"Availability bits vary by scenario, but the ordered candidate names for these ids are stable across the checked saves."
|
||||
],
|
||||
"bindings": [
|
||||
{
|
||||
"descriptor_id": 521,
|
||||
"candidate_id": 18,
|
||||
"candidate_name": "FarmGrain",
|
||||
"binding_index": 19,
|
||||
"binding_source": "rt3_105_candidate_table"
|
||||
},
|
||||
{
|
||||
"descriptor_id": 526,
|
||||
"candidate_id": 23,
|
||||
"candidate_name": "Furniture Factory",
|
||||
"binding_index": 24,
|
||||
"binding_source": "rt3_105_candidate_table"
|
||||
},
|
||||
{
|
||||
"descriptor_id": 528,
|
||||
"candidate_id": 25,
|
||||
"candidate_name": "Logging Camp",
|
||||
"binding_index": 26,
|
||||
"binding_source": "rt3_105_candidate_table"
|
||||
},
|
||||
{
|
||||
"descriptor_id": 548,
|
||||
"candidate_id": 45,
|
||||
"candidate_name": "Port01",
|
||||
"binding_index": 46,
|
||||
"binding_source": "rt3_105_candidate_table"
|
||||
},
|
||||
{
|
||||
"descriptor_id": 563,
|
||||
"candidate_id": 60,
|
||||
"candidate_name": "Warehouse05",
|
||||
"binding_index": 61,
|
||||
"binding_source": "rt3_105_candidate_table"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -4694,7 +4694,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 521,
|
||||
"label": "Add Building Slot 19",
|
||||
"label": "Add Building FarmGrain",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_building_spawn",
|
||||
"runtime_key": null,
|
||||
|
|
@ -4739,7 +4739,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 526,
|
||||
"label": "Add Building Slot 24",
|
||||
"label": "Add Building Furniture Factory",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_building_spawn",
|
||||
"runtime_key": null,
|
||||
|
|
@ -4757,7 +4757,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 528,
|
||||
"label": "Add Building Slot 26",
|
||||
"label": "Add Building Logging Camp",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_building_spawn",
|
||||
"runtime_key": null,
|
||||
|
|
@ -4937,7 +4937,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 548,
|
||||
"label": "Add Building Slot 46",
|
||||
"label": "Add Building Port01",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_building_spawn",
|
||||
"runtime_key": null,
|
||||
|
|
@ -5072,7 +5072,7 @@
|
|||
},
|
||||
{
|
||||
"descriptor_id": 563,
|
||||
"label": "Add Building Slot 61",
|
||||
"label": "Add Building Warehouse05",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_building_spawn",
|
||||
"runtime_key": null,
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ enum Command {
|
|||
RuntimeInspectSmp {
|
||||
smp_path: PathBuf,
|
||||
},
|
||||
RuntimeInspectCandidateTable {
|
||||
smp_path: PathBuf,
|
||||
},
|
||||
RuntimeInspectCompactEventDispatchCluster {
|
||||
root_path: PathBuf,
|
||||
},
|
||||
|
|
@ -521,6 +524,34 @@ struct RuntimeCandidateTableSample {
|
|||
availability_by_name: BTreeMap<String, u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RuntimeCandidateTableEntrySample {
|
||||
index: usize,
|
||||
offset: usize,
|
||||
text: String,
|
||||
availability_dword: u32,
|
||||
availability_dword_hex: String,
|
||||
trailer_word: u32,
|
||||
trailer_word_hex: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RuntimeCandidateTableInspectionReport {
|
||||
path: String,
|
||||
profile_family: String,
|
||||
source_kind: String,
|
||||
semantic_family: String,
|
||||
header_word_0_hex: String,
|
||||
header_word_1_hex: String,
|
||||
header_word_2_hex: String,
|
||||
observed_entry_capacity: usize,
|
||||
observed_entry_count: usize,
|
||||
zero_trailer_entry_count: usize,
|
||||
nonzero_trailer_entry_count: usize,
|
||||
zero_trailer_entry_names: Vec<String>,
|
||||
entries: Vec<RuntimeCandidateTableEntrySample>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RuntimeCandidateTableComparisonReport {
|
||||
file_count: usize,
|
||||
|
|
@ -946,6 +977,9 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
Command::RuntimeInspectSmp { smp_path } => {
|
||||
run_runtime_inspect_smp(&smp_path)?;
|
||||
}
|
||||
Command::RuntimeInspectCandidateTable { smp_path } => {
|
||||
run_runtime_inspect_candidate_table(&smp_path)?;
|
||||
}
|
||||
Command::RuntimeInspectCompactEventDispatchCluster { root_path } => {
|
||||
run_runtime_inspect_compact_event_dispatch_cluster(&root_path)?;
|
||||
}
|
||||
|
|
@ -1167,6 +1201,13 @@ fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
|
|||
smp_path: PathBuf::from(path),
|
||||
})
|
||||
}
|
||||
[command, subcommand, path]
|
||||
if command == "runtime" && subcommand == "inspect-candidate-table" =>
|
||||
{
|
||||
Ok(Command::RuntimeInspectCandidateTable {
|
||||
smp_path: PathBuf::from(path),
|
||||
})
|
||||
}
|
||||
[command, subcommand, root_path]
|
||||
if command == "runtime"
|
||||
&& subcommand == "inspect-compact-event-dispatch-cluster" =>
|
||||
|
|
@ -1459,7 +1500,7 @@ fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
|
|||
})
|
||||
}
|
||||
_ => Err(
|
||||
"usage: rrt-cli [validate [repo-root] | finance eval <snapshot.json> | finance diff <left.json> <right.json> | runtime validate-fixture <fixture.json> | runtime summarize-fixture <fixture.json> | runtime export-fixture-state <fixture.json> <snapshot.json> | runtime diff-state <left.json> <right.json> | runtime summarize-state <snapshot.json> | runtime import-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime inspect-compact-event-dispatch-cluster <maps-dir> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime inspect-save-company-chairman <file.smp> | runtime inspect-save-placed-structure-triplets <file.smp> | runtime compare-region-fixed-row-runs <left.gms> <right.gms> | runtime inspect-periodic-company-service-trace <file.smp> | runtime inspect-region-service-trace <file.smp> | runtime inspect-infrastructure-asset-trace <file.smp> | runtime inspect-save-region-queued-notice-records <file.smp> | runtime inspect-placed-structure-dynamic-side-buffer <file.smp> | runtime inspect-unclassified-save-collections <file.smp> | runtime import-save-state <file.smp> <snapshot.json> | runtime export-save-slice <file.smp> <save-slice.json> | runtime export-overlay-import <snapshot.json> <save-slice.json> <overlay-import.json> | runtime inspect-pk4 <file.pk4> | runtime inspect-cargo-types <CargoTypes-dir> | runtime inspect-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-production-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-price-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-win <file.win> | runtime extract-pk4-entry <file.pk4> <entry-name> <output-path> | runtime inspect-campaign-exe <RT3.exe> | runtime compare-classic-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-105-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-candidate-table <file1> <file2> [fileN...] | runtime compare-recipe-book-lines <file1> <file2> [fileN...] | runtime compare-setup-payload-core <file1> <file2> [fileN...] | runtime compare-setup-launch-payload <file1> <file2> [fileN...] | runtime compare-post-special-conditions-scalars <file1> <file2> [fileN...] | runtime scan-candidate-table-headers <root-dir> | runtime scan-special-conditions <root-dir> | runtime scan-aligned-runtime-rule-band <root-dir> | runtime scan-post-special-conditions-scalars <root-dir> | runtime scan-post-special-conditions-tail <root-dir> | runtime scan-recipe-book-lines <root-dir> | runtime export-profile-block <save.gms> <profile.json>]"
|
||||
"usage: rrt-cli [validate [repo-root] | finance eval <snapshot.json> | finance diff <left.json> <right.json> | runtime validate-fixture <fixture.json> | runtime summarize-fixture <fixture.json> | runtime export-fixture-state <fixture.json> <snapshot.json> | runtime diff-state <left.json> <right.json> | runtime summarize-state <snapshot.json> | runtime import-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime inspect-candidate-table <file.smp> | runtime inspect-compact-event-dispatch-cluster <maps-dir> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime inspect-save-company-chairman <file.smp> | runtime inspect-save-placed-structure-triplets <file.smp> | runtime compare-region-fixed-row-runs <left.gms> <right.gms> | runtime inspect-periodic-company-service-trace <file.smp> | runtime inspect-region-service-trace <file.smp> | runtime inspect-infrastructure-asset-trace <file.smp> | runtime inspect-save-region-queued-notice-records <file.smp> | runtime inspect-placed-structure-dynamic-side-buffer <file.smp> | runtime inspect-unclassified-save-collections <file.smp> | runtime import-save-state <file.smp> <snapshot.json> | runtime export-save-slice <file.smp> <save-slice.json> | runtime export-overlay-import <snapshot.json> <save-slice.json> <overlay-import.json> | runtime inspect-pk4 <file.pk4> | runtime inspect-cargo-types <CargoTypes-dir> | runtime inspect-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-production-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-price-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-win <file.win> | runtime extract-pk4-entry <file.pk4> <entry-name> <output-path> | runtime inspect-campaign-exe <RT3.exe> | runtime compare-classic-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-105-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-candidate-table <file1> <file2> [fileN...] | runtime compare-recipe-book-lines <file1> <file2> [fileN...] | runtime compare-setup-payload-core <file1> <file2> [fileN...] | runtime compare-setup-launch-payload <file1> <file2> [fileN...] | runtime compare-post-special-conditions-scalars <file1> <file2> [fileN...] | runtime scan-candidate-table-headers <root-dir> | runtime scan-special-conditions <root-dir> | runtime scan-aligned-runtime-rule-band <root-dir> | runtime scan-post-special-conditions-scalars <root-dir> | runtime scan-post-special-conditions-tail <root-dir> | runtime scan-recipe-book-lines <root-dir> | runtime export-profile-block <save.gms> <profile.json>]"
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
|
|
@ -2246,6 +2287,12 @@ fn run_runtime_compare_candidate_table(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn run_runtime_inspect_candidate_table(smp_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let report = load_candidate_table_inspection_report(smp_path)?;
|
||||
println!("{}", serde_json::to_string_pretty(&report)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_runtime_compare_recipe_book_lines(
|
||||
smp_paths: &[PathBuf],
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -3119,6 +3166,161 @@ fn load_candidate_table_sample(
|
|||
})
|
||||
}
|
||||
|
||||
fn load_candidate_table_inspection_report(
|
||||
smp_path: &Path,
|
||||
) -> Result<RuntimeCandidateTableInspectionReport, Box<dyn std::error::Error>> {
|
||||
let inspection = inspect_smp_file(smp_path)?;
|
||||
if let Some(probe) = inspection.rt3_105_save_name_table_probe {
|
||||
return Ok(RuntimeCandidateTableInspectionReport {
|
||||
path: smp_path.display().to_string(),
|
||||
profile_family: probe.profile_family,
|
||||
source_kind: probe.source_kind,
|
||||
semantic_family: probe.semantic_family,
|
||||
header_word_0_hex: probe.header_word_0_hex,
|
||||
header_word_1_hex: probe.header_word_1_hex,
|
||||
header_word_2_hex: probe.header_word_2_hex,
|
||||
observed_entry_capacity: probe.observed_entry_capacity,
|
||||
observed_entry_count: probe.observed_entry_count,
|
||||
zero_trailer_entry_count: probe.zero_trailer_entry_count,
|
||||
nonzero_trailer_entry_count: probe.nonzero_trailer_entry_count,
|
||||
zero_trailer_entry_names: probe.zero_trailer_entry_names,
|
||||
entries: probe
|
||||
.entries
|
||||
.into_iter()
|
||||
.map(|entry| RuntimeCandidateTableEntrySample {
|
||||
index: entry.index,
|
||||
offset: entry.offset,
|
||||
text: entry.text,
|
||||
availability_dword: entry.availability_dword,
|
||||
availability_dword_hex: entry.availability_dword_hex,
|
||||
trailer_word: entry.trailer_word,
|
||||
trailer_word_hex: entry.trailer_word_hex,
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
|
||||
let bytes = fs::read(smp_path)?;
|
||||
let header_offset = 0x6a70usize;
|
||||
let entries_offset = 0x6ad1usize;
|
||||
let block_end_offset = 0x73c0usize;
|
||||
let entry_stride = 0x22usize;
|
||||
if bytes.len() < block_end_offset
|
||||
|| !matches_candidate_table_header_bytes(&bytes, header_offset)
|
||||
{
|
||||
return Err(format!(
|
||||
"{} did not expose an RT3 1.05 candidate-availability table",
|
||||
smp_path.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let observed_entry_capacity = read_u32_le(&bytes, header_offset + 0x1c)
|
||||
.ok_or_else(|| format!("{} is missing candidate table capacity", smp_path.display()))?
|
||||
as usize;
|
||||
let observed_entry_count = read_u32_le(&bytes, header_offset + 0x20)
|
||||
.ok_or_else(|| format!("{} is missing candidate table count", smp_path.display()))?
|
||||
as usize;
|
||||
if observed_entry_capacity < observed_entry_count {
|
||||
return Err(format!(
|
||||
"{} has invalid candidate table capacity/count {observed_entry_capacity}/{observed_entry_count}",
|
||||
smp_path.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let entries_end_offset = entries_offset
|
||||
.checked_add(
|
||||
observed_entry_count
|
||||
.checked_mul(entry_stride)
|
||||
.ok_or("candidate table length overflow")?,
|
||||
)
|
||||
.ok_or("candidate table end overflow")?;
|
||||
if entries_end_offset > block_end_offset {
|
||||
return Err(format!(
|
||||
"{} candidate table overruns fixed block end",
|
||||
smp_path.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let mut zero_trailer_entry_names = Vec::new();
|
||||
let mut entries = Vec::new();
|
||||
for index in 0..observed_entry_count {
|
||||
let offset = entries_offset + index * entry_stride;
|
||||
let chunk = &bytes[offset..offset + entry_stride];
|
||||
let nul_index = chunk
|
||||
.iter()
|
||||
.position(|byte| *byte == 0)
|
||||
.unwrap_or(entry_stride - 4);
|
||||
let text = std::str::from_utf8(&chunk[..nul_index]).map_err(|_| {
|
||||
format!(
|
||||
"{} contains invalid UTF-8 in candidate table",
|
||||
smp_path.display()
|
||||
)
|
||||
})?;
|
||||
let availability_dword =
|
||||
read_u32_le(&bytes, offset + entry_stride - 4).ok_or_else(|| {
|
||||
format!(
|
||||
"{} is missing candidate availability dword",
|
||||
smp_path.display()
|
||||
)
|
||||
})?;
|
||||
if availability_dword == 0 {
|
||||
zero_trailer_entry_names.push(text.to_string());
|
||||
}
|
||||
entries.push(RuntimeCandidateTableEntrySample {
|
||||
index,
|
||||
offset,
|
||||
text: text.to_string(),
|
||||
availability_dword,
|
||||
availability_dword_hex: format!("0x{availability_dword:08x}"),
|
||||
trailer_word: availability_dword,
|
||||
trailer_word_hex: format!("0x{availability_dword:08x}"),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(RuntimeCandidateTableInspectionReport {
|
||||
path: smp_path.display().to_string(),
|
||||
profile_family: classify_candidate_table_header_profile(
|
||||
smp_path
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.map(|ext| ext.to_ascii_lowercase()),
|
||||
&bytes,
|
||||
),
|
||||
source_kind: match smp_path
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.map(|ext| ext.to_ascii_lowercase())
|
||||
.as_deref()
|
||||
{
|
||||
Some("gmp") => "map-fixed-catalog-range",
|
||||
Some("gms") => "save-fixed-catalog-range",
|
||||
_ => "fixed-catalog-range",
|
||||
}
|
||||
.to_string(),
|
||||
semantic_family: "scenario-named-candidate-availability-table".to_string(),
|
||||
header_word_0_hex: format!(
|
||||
"0x{:08x}",
|
||||
read_u32_le(&bytes, header_offset).ok_or("missing candidate header word 0")?
|
||||
),
|
||||
header_word_1_hex: format!(
|
||||
"0x{:08x}",
|
||||
read_u32_le(&bytes, header_offset + 4).ok_or("missing candidate header word 1")?
|
||||
),
|
||||
header_word_2_hex: format!(
|
||||
"0x{:08x}",
|
||||
read_u32_le(&bytes, header_offset + 8).ok_or("missing candidate header word 2")?
|
||||
),
|
||||
observed_entry_capacity,
|
||||
observed_entry_count,
|
||||
zero_trailer_entry_count: zero_trailer_entry_names.len(),
|
||||
nonzero_trailer_entry_count: observed_entry_count - zero_trailer_entry_names.len(),
|
||||
zero_trailer_entry_names,
|
||||
entries,
|
||||
})
|
||||
}
|
||||
|
||||
fn load_recipe_book_line_sample(
|
||||
smp_path: &Path,
|
||||
) -> Result<RuntimeRecipeBookLineSample, Box<dyn std::error::Error>> {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ pub const REQUIRED_EXPORTS: &[&str] = &[
|
|||
"artifacts/exports/rt3-1.06/pending-template-store-management.md",
|
||||
"artifacts/exports/rt3-1.06/event-effects-table.json",
|
||||
"artifacts/exports/rt3-1.06/event-effects-cargo-bindings.json",
|
||||
"artifacts/exports/rt3-1.06/event-effects-building-bindings.json",
|
||||
"artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json",
|
||||
"artifacts/exports/rt3-1.06/economy-cargo-sources.json",
|
||||
"artifacts/exports/rt3-1.06/selected-year-bucket-ladder.json",
|
||||
|
|
|
|||
|
|
@ -289,18 +289,21 @@ Working rule:
|
|||
cover the full `614`-row export instead of the old truncated `520`-row slice
|
||||
- that closes the earlier unlabeled cluster:
|
||||
grouped descriptor ids `521`, `526`, `528`, `548`, and `563` are now recovered as
|
||||
`Add Building Slot 19`, `Add Building Slot 24`, `Add Building Slot 26`, `Add Building Slot 46`,
|
||||
and `Add Building Slot 61` respectively, all in the widened shell-owned add-building strip
|
||||
`503..613`
|
||||
`Add Building FarmGrain`, `Add Building Furniture Factory`, `Add Building Logging Camp`,
|
||||
`Add Building Port01`, and `Add Building Warehouse05` respectively. The checked-in
|
||||
`event-effects-building-bindings.json` artifact grounds those names from the stable RT3 1.05
|
||||
candidate-table order plus the direct `descriptor_id - 503` candidate-id bridge in
|
||||
`0x00430270`
|
||||
- the earlier `label_id - 2000` bridge for `548` and `563` is now known to be a false lead:
|
||||
those numeric collisions hit the special-condition label table
|
||||
(`Disable Building Stations`, `Completely Disable Money-Related Things`), but the extended
|
||||
EventEffects table proves the actual grouped descriptors are add-building slots, not
|
||||
special-condition verbs
|
||||
- the compact opcode-`8` frontier therefore shifts:
|
||||
the next static-analysis pass should target which add-building slot numbers correspond to which
|
||||
concrete building classes and whether opcode `8` on that shell-owned strip means a distinct
|
||||
add-building shell flow, not more missing-label recovery
|
||||
the next static-analysis pass should widen the concrete add-building candidate-name bridge
|
||||
beyond the already grounded `521/526/528/548/563` rows and then determine whether opcode `8`
|
||||
on that shell-owned strip means a distinct add-building shell flow, not more missing-label
|
||||
recovery
|
||||
- the concrete owner strip above that bundle is grounded now too:
|
||||
`0x00433060` is the direct non-direct serializer loop that writes `0x4e99/0x4e9a/0x4e9b`,
|
||||
calls `0x00430d70` per live collection row, and sits beside the sibling `0x00433130` size/load
|
||||
|
|
|
|||
|
|
@ -115,8 +115,21 @@ def load_cargo_bindings(raw_table_path: Path) -> dict[int, dict[str, object]]:
|
|||
}
|
||||
|
||||
|
||||
def load_building_bindings(raw_table_path: Path) -> dict[int, dict[str, object]]:
|
||||
bindings_path = raw_table_path.parent / "event-effects-building-bindings.json"
|
||||
if not bindings_path.exists():
|
||||
return {}
|
||||
artifact = json.loads(bindings_path.read_text(encoding="utf-8"))
|
||||
return {
|
||||
int(binding["descriptor_id"]): binding
|
||||
for binding in artifact.get("bindings", [])
|
||||
}
|
||||
|
||||
|
||||
def classify(
|
||||
row: dict[str, object], cargo_bindings: dict[int, dict[str, object]]
|
||||
row: dict[str, object],
|
||||
cargo_bindings: dict[int, dict[str, object]],
|
||||
building_bindings: dict[int, dict[str, object]],
|
||||
) -> dict[str, object]:
|
||||
descriptor_id = int(row["descriptor_id"])
|
||||
label = str(row["label"])
|
||||
|
|
@ -223,6 +236,10 @@ def classify(
|
|||
executable_in_runtime = True
|
||||
elif 503 <= descriptor_id <= 613:
|
||||
parameter_family = "world_building_spawn"
|
||||
binding = building_bindings.get(descriptor_id)
|
||||
if binding is not None:
|
||||
label = f"Add Building {binding['candidate_name']}"
|
||||
else:
|
||||
label = f"Add Building Slot {descriptor_id - 502}"
|
||||
runtime_status = "shell_owned"
|
||||
elif "Earthquake" in label or "Storm" in label:
|
||||
|
|
@ -249,7 +266,11 @@ def main() -> None:
|
|||
|
||||
raw_artifact = json.loads(args.raw_table.read_text(encoding="utf-8"))
|
||||
cargo_bindings = load_cargo_bindings(args.raw_table)
|
||||
descriptors = [classify(row, cargo_bindings) for row in raw_artifact["descriptors"]]
|
||||
building_bindings = load_building_bindings(args.raw_table)
|
||||
descriptors = [
|
||||
classify(row, cargo_bindings, building_bindings)
|
||||
for row in raw_artifact["descriptors"]
|
||||
]
|
||||
artifact = {
|
||||
"descriptor_count": len(descriptors),
|
||||
"raw_table_binary_sha256": raw_artifact.get("binary_sha256"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue