Added Platforms parsing

+Added support for parsing Platforms
+Added glb_bounds.py - a script for extracting bounding boxes from GLB files
*Updated scp.py to not ignore MiscGroups and Platforms
This commit is contained in:
izawartka 2025-07-19 12:26:23 +02:00
parent c6b6fef724
commit 87b2091333
6 changed files with 789 additions and 5 deletions

View File

@ -51,6 +51,7 @@ const Constants = {
connectTracksFailed: true,
routeInvalidSegment: true,
derailerUnknownDirection: true,
platformUndefinedPrefabName: true,
endMiscGroupWithoutStart: true,
},
errors: {

View File

@ -0,0 +1,567 @@
import Vector3 from "../vector3.js";
/*
NOTE: VSCode regex for replacing vector3 values in text:
\{\s*"x"\s*:\s*(-?\d+(?:\.\d+)?),\s*"y"\s*:\s*(-?\d+(?:\.\d+)?),\s*"z"\s*:\s*(-?\d+(?:\.\d+)?)\s*\}(,?)\n
replace to
new Vector3($1, $2, $3)$4\n
*/
const DefinedPlatforms = {
"peron_v1-1": {
"center": new Vector3(3.585, 0.056, 0.0),
"size": new Vector3(4.002, 0.65, 10.035)
},
"peron_v1-2": {
"alias": "peron_v1-1"
},
"peron_v2": {
"alias": "peron_v1-1"
},
"peron_v3-1": {
"alias": "peron_v1-1"
},
"peron_v3-2": {
"alias": "peron_v1-1"
},
"peron_v4": {
"alias": "peron_v1-1"
},
"peron_v5-1": {
"center": new Vector3(3.675, 0.312, 0.0),
"size": new Vector3(4.002, 1.301, 10.035)
},
"peron_v5-2": {
"alias": "peron_v5-1"
},
"peron_zm_200m_v1_new": {
"center": new Vector3(-4.175, -0.06, 0.0),
"size": new Vector3(5.0, 1.76, 200.0)
},
"peron_zm_200m_v1_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v2_new": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v2_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v3_new": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v3_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v4_new": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v4_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v5_new": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v5_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v6_new": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v6_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v7_new": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_200m_v7_normal": {
"alias": "peron_zm_200m_v1_new"
},
"peron_zm_250m_v1_new": {
"center": new Vector3(-4.175, -0.06, 0.0),
"size": new Vector3(5.0, 1.76, 250.0)
},
"peron_zm_250m_v1_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v2_new": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v2_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v3_new": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v3_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v4_new": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v4_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v5_new": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v5_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v6_new": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v6_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v7_new": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_250m_v7_normal": {
"alias": "peron_zm_250m_v1_new"
},
"peron_zm_300m_v1_new": {
"center": new Vector3(-4.175, -0.06, -0.0),
"size": new Vector3(5.0, 1.76, 300.0)
},
"peron_zm_300m_v1_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v2_new": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v2_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v3_new": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v3_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v4_new": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v4_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v5_new": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v5_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v6_new": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v6_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v7_new": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_300m_v7_normal": {
"alias": "peron_zm_300m_v1_new"
},
"peron_zm_30m_middle_v1_new": {
"center": new Vector3(-5.425, -0.06, 0.0),
"size": new Vector3(2.5, 1.76, 30.0)
},
"peron_zm_30m_middle_v1_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v2_new": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v2_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v3_new": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v3_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v4_new": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v4_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v5_new": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v5_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v6_new": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v6_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v7_new": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_middle_v7_normal": {
"alias": "peron_zm_30m_middle_v1_new"
},
"peron_zm_30m_thin_v1_new": {
"center": new Vector3(-3.175, -0.06, 0.0),
"size": new Vector3(3.0, 1.76, 30.0)
},
"peron_zm_30m_thin_v1_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v2_new": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v2_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v3_new": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v3_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v4_new": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v4_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v5_new": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v5_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v6_new": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v6_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v7_new": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_thin_v7_normal": {
"alias": "peron_zm_30m_thin_v1_new"
},
"peron_zm_30m_v1_new": {
"center": new Vector3(-4.175, -0.06, 0.0),
"size": new Vector3(5.0, 1.76, 30.0)
},
"peron_zm_30m_v1_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v2_new": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v2_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v3_new": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v3_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v4_new": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v4_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v5_new": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v5_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v6_new": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v6_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v7_new": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_30m_v7_normal": {
"alias": "peron_zm_30m_v1_new"
},
"peron_zm_6m_middle_v1_new": {
"center": new Vector3(-5.425, -0.06, -0.0),
"size": new Vector3(2.5, 1.76, 6.0)
},
"peron_zm_6m_middle_v1_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v2_new": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v2_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v3_new": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v3_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v4_new": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v4_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v5_new": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v5_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v6_new": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v6_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v7_new": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_middle_v7_normal": {
"alias": "peron_zm_6m_middle_v1_new"
},
"peron_zm_6m_thin_v1_new": {
"center": new Vector3(-3.175, -0.06, 0.0),
"size": new Vector3(3.0, 1.76, 6.0)
},
"peron_zm_6m_thin_v1_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v2_new": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v2_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v3_new": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v3_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v4_new": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v4_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v5_new": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v5_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v6_new": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v6_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v7_new": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_thin_v7_normal": {
"alias": "peron_zm_6m_thin_v1_new"
},
"peron_zm_6m_v1_new": {
"center": new Vector3(-4.175, -0.06, -0.0),
"size": new Vector3(5.0, 1.76, 6.0)
},
"peron_zm_6m_v1_normal": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v2_new": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v2_normal": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v3_new": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v3_normal": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v4_new": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v4_normal": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v5_new": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v5_normal": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v6_new": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v6_normal": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v7_new": {
"alias": "peron_zm_6m_v1_new"
},
"peron_zm_6m_v7_normal": {
"alias": "peron_zm_6m_v1_new"
},
"platform1newsnap": {
"center": new Vector3(4.58, 0.15, -4.56),
"size": new Vector3(5.551, 1.0, 10.0)
},
"platform1newsnaplong": {
"center": new Vector3(4.32, 0.15, 10.437),
"size": new Vector3(5.273, 1.0, 39.995)
},
"platform2newsnap": {
"center": new Vector3(4.58, 0.15, -4.56),
"size": new Vector3(5.551, 1.0, 10.0)
},
"platform2newsnaplong": {
"center": new Vector3(4.32, 0.15, 10.437),
"size": new Vector3(5.273, 1.0, 39.995)
},
"platform3_snap": {
"center": new Vector3(2.74, -0.162, 0.0),
"size": new Vector3(2.0, 0.4, 8.0)
},
"platform_2S_8_5m": {
"center": new Vector3(0.0, 0.3, 2.5),
"size": new Vector3(8.5, 0.6, 5.0)
},
"platform_concrete_3m_1S": {
"center": new Vector3(0.0, 0.3, 3.0),
"size": new Vector3(3.0, 0.6, 6.0)
},
"platform_concrete_6m_2S": {
"center": new Vector3(0.0, 0.3, 3.0),
"size": new Vector3(6.0, 0.6, 6.0)
},
"platform_gorzow_wlkp_01": {
"center": new Vector3(0.0, 0.15, 0.0),
"size": new Vector3(10.0, 0.3, 2.8)
},
"platform_gorzow_wlkp_02": {
"center": new Vector3(0.0, 0.15, 0.0),
"size": new Vector3(10.0, 0.3, 2.8)
},
"platform_gorzow_wlkp_03": {
"alias": "platform_gorzow_wlkp_01"
},
"platform_gorzow_wlkp_04": {
"alias": "platform_gorzow_wlkp_01"
},
"platform_new_01": {
"center": new Vector3(-0.2, 0.5, -0.0),
"size": new Vector3(5.551, 1.0, 10.0)
},
"platform_new_02": {
"center": new Vector3(-0.2, 0.5, -0.0),
"size": new Vector3(5.551, 1.0, 10.0)
},
"platform_new_03": {
"center": new Vector3(-1.0, 0.5, -0.0),
"size": new Vector3(5.551, 1.0, 10.0)
},
"platform_new_03_snap": {
"center": new Vector3(4.48, 0.15, -4.56),
"size": new Vector3(5.551, 1.0, 10.0)
},
"platform_new_end_left": {
"center": new Vector3(-0.128, 0.5, 0.01),
"size": new Vector3(4.3, 1.0, 10.0)
},
"platform_new_end_right": {
"center": new Vector3(-0.15, 0.5, 0.0),
"size": new Vector3(4.3, 1.0, 10.0)
},
"platform_new_thin_01": {
"center": new Vector3(-1.8, 0.5, -0.0),
"size": new Vector3(3.551, 1.0, 10.0)
},
"platform_new_thin_02": {
"alias": "platform_new_thin_01"
},
"platform_new_thin_03": {
"center": new Vector3(-2.0, 0.5, -0.0),
"size": new Vector3(3.551, 1.0, 10.0)
},
"platform_new_thin_03_snap": {
"center": new Vector3(3.48, 0.15, -4.56),
"size": new Vector3(3.551, 1.0, 10.0)
},
"platform_new_two_sides_01": {
"center": new Vector3(0.0, 0.5, -0.0),
"size": new Vector3(7.55, 1.0, 10.0)
},
"platform_new_two_sides_02": {
"center": new Vector3(0.0, 0.5, -0.0),
"size": new Vector3(7.55, 1.0, 10.0)
},
"platform_new_two_sides_03": {
"center": new Vector3(0.0, 0.5, -0.0),
"size": new Vector3(7.55, 1.0, 10.0)
},
"platform_new_two_sides_04": {
"center": new Vector3(0.0, 0.5, -0.0),
"size": new Vector3(8.53, 1.0, 10.0)
},
"platform_new_two_sides_thin_03": {
"center": new Vector3(0.0, 0.5, -0.0),
"size": new Vector3(5.551, 1.0, 10.001)
},
"platform_new_wide_03": {
"center": new Vector3(-0.25, 0.5, -0.0),
"size": new Vector3(7.05, 1.0, 10.0)
},
"platform_new_wide_03_snap": {
"center": new Vector3(5.23, 0.15, -4.56),
"size": new Vector3(7.05, 1.0, 10.0)
},
"platform_olawa_01": {
"center": new Vector3(0.0, 0.15, 0.0),
"size": new Vector3(10.0, 0.3, 5.25)
},
"platform_olawa_02": {
"center": new Vector3(0.0, 0.15, 0.0),
"size": new Vector3(10.0, 0.3, 2.083)
},
"platform_old": {
"alias": "platform_new_end_right"
},
"platform_old_alt_stripe": {
"center": new Vector3(-0.0, 0.5, 0.0),
"size": new Vector3(4.0, 1.0, 10.0)
},
"platform_old_alt_stripe_2": {
"alias": "platform_old_alt_stripe"
},
"platform_old_end_left": {
"alias": "platform_new_end_right"
},
"platform_old_end_right": {
"alias": "platform_new_end_right"
},
"platform_old_no_stripe": {
"center": new Vector3(-0.15, 0.19, 0.0),
"size": new Vector3(4.3, 1.0, 10.0)
}
};
export default DefinedPlatforms;

View File

@ -0,0 +1,49 @@
import Misc from "./misc.js";
import SceneryParserLog from "../scenery-parser-log.js";
import Vector3 from "../vector3.js";
import DefinedPlatforms from "../defs/defined-platforms.js";
export default class Platform extends Misc {
type = "Platform";
def = null;
constructor(id, misc_id, prefab_name, pos, rot, name) {
super(id, misc_id, prefab_name, pos, rot, name);
this.def = Platform.getDef(name, prefab_name);
}
static isPlatform(prefabName) {
const regex = /^(platform|peron|wgt_peron)/i;
return regex.test(prefabName);
}
static fromText(id, text, miscGroups = []) {
const values = text.split(";");
const object = new Platform(
id, // id
values[1], // misc_id
values[2], // prefab_name
...Misc.applyGroupTransforms(
Vector3.fromValuesArray(values, 3), // pos
Vector3.fromValuesArray(values, 6), // rot
miscGroups
),
values[9] // name
);
object.miscGroups = [...miscGroups];
return object;
}
static getDef(name, prefabName) {
let def = DefinedPlatforms[prefabName];
if (!def) {
SceneryParserLog.warn('platformUndefinedPrefabName', `Platform ${name} has an undefined prefab name ${prefabName}`);
}
if(def.alias) return Platform.getDef(name, def.alias);
return def;
}
}

View File

@ -17,6 +17,7 @@ import ElectrificationResolver from './electrification-resolver';
import NEVP from './track-objects/nevp';
import Derailer from './track-objects/derailer';
import SpawnPoint from './track-objects/spawn-point';
import Platform from './misc/platform';
import { attachSigns } from './attach-signs';
import {connectTracks} from "./connect-tracks";
import MiscGroup from './misc-group';
@ -174,7 +175,9 @@ export default class SceneryParser {
const prefabName = text.split(';', 4)[2];
const id = SceneryParser.nextMiscId++;
if(SignalBox.isSignalBox(prefabName)) {
if (Platform.isPlatform(prefabName)) {
return Platform.fromText(id, text, miscGroups);
} else if(SignalBox.isSignalBox(prefabName)) {
return SignalBox.fromText(id, text, miscGroups);
} else if(Constants.parser.skipBaseMisc) {
return null;

162
tools/glb_bounds.py Normal file
View File

@ -0,0 +1,162 @@
import argparse
import os
import json
import logging
from tqdm import tqdm
import trimesh
def parse_args():
parser = argparse.ArgumentParser(
description="Extract bounding boxes from GLB mesh files and output JSON summary."
)
parser.add_argument(
'input',
help='Input file or directory containing .glb files'
)
parser.add_argument(
'output',
help='Output JSON file path'
)
parser.add_argument(
'--decimal_places', '-d',
type=int,
default=3,
help='Number of decimal places for output coordinates (default: 3)'
)
parser.add_argument(
'--no_aliases', '-a',
action='store_false',
help='Disable aliases in the output JSON (default: false)'
)
return parser.parse_args()
def round_floats(obj, prec=3):
if isinstance(obj, float):
return round(obj, prec)
elif isinstance(obj, dict):
return {k: round_floats(v, prec) for k, v in obj.items()}
elif isinstance(obj, list):
return [round_floats(v, prec) for v in obj]
else:
return obj
def collect_glb_files(path):
"""
Given a path, return a list of .glb files.
If path is a directory, walk it; if file, return single-element list.
"""
glb_files = []
if os.path.isdir(path):
for root, _, files in os.walk(path):
for name in files:
if name.lower().endswith('.glb'):
glb_files.append(os.path.join(root, name))
elif os.path.isfile(path) and path.lower().endswith('.glb'):
glb_files = [path]
else:
logging.error(f"Input path '{path}' is neither a .glb file nor a directory containing them.")
return glb_files
def process_file(filepath):
"""
Load a GLB file, compute its center and size, return a dict entry.
Returns None if fails.
"""
try:
mesh = trimesh.load(filepath, force='mesh')
if mesh.is_empty:
logging.warning(f"Mesh in '{filepath}' is empty, skipping.")
return None
except Exception as e:
logging.warning(f"Failed to load '{filepath}' as a mesh: {e}")
return None
# Compute axis-aligned bounding box
bounds = mesh.bounds # shape (2,3): [min, max]
min_pt, max_pt = bounds
center = (min_pt + max_pt) / 2.0
size = max_pt - min_pt
# y is the top axis by convention
entry = {
'center': {
'x': float(center[0]),
'y': float(center[1]),
'z': float(center[2]),
},
'size': {
'x': float(size[0]),
'y': float(size[1]),
'z': float(size[2]),
}
}
return entry
def items_equal(item1, item2):
if isinstance(item1, dict) and isinstance(item2, dict):
if item1.keys() != item2.keys():
return False
return all(items_equal(item1[k], item2[k]) for k in item1)
elif isinstance(item1, list) and isinstance(item2, list):
if len(item1) != len(item2):
return False
return all(items_equal(i1, i2) for i1, i2 in zip(item1, item2))
elif isinstance(item1, (int, float)) and isinstance(item2, (int, float)):
return round(item1, 6) == round(item2, 6)
else:
return item1 == item2
def find_apply_aliases(results):
logging.info("Applying aliases...")
final_results = {}
for name, entry in results.items():
if not entry:
continue
found_alias = False
for existing_name, existing_entry in final_results.items():
if 'alias' in existing_entry:
continue
if not items_equal(entry, existing_entry):
continue
final_results[name] = {
'alias': existing_name
}
found_alias = True
break
if not found_alias:
final_results[name] = entry
return final_results
def main():
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
args = parse_args()
glb_files = collect_glb_files(args.input)
if not glb_files:
logging.error("No .glb files found to process.")
return
results = {}
for filepath in tqdm(glb_files, desc="Processing GLB files"):
entry = process_file(filepath)
if entry:
prefab_name = os.path.splitext(os.path.basename(filepath))[0]
results[prefab_name] = entry
# Write output JSON
try:
with open(args.output, 'w') as f:
results_final = find_apply_aliases(results) if args.no_aliases else results
json.dump(round_floats(results_final, args.decimal_places), f, indent=4)
logging.info(f"Successfully wrote {len(results)} entries to '{args.output}'")
except Exception as e:
logging.error(f"Failed to write output JSON: {e}")
if __name__ == '__main__':
main()

View File

@ -1,13 +1,15 @@
import os
import re
import sys
#
# [ TD2 SCENERY PROCESSOR ]
# by masuo
# v1.5
# v1.6
#
BAD_WORDS = ['EndMiscGroup', 'Fence', 'TerrainPoint', 'Wires']
BAD_WORDS = ['Fence', 'TerrainPoint', 'Wires']
MISC_REGEX = r'^(?:SignalBox|wgt_peron|peron|platform).*$'
def should_exclude(line: str) -> bool:
for word in BAD_WORDS:
@ -15,8 +17,8 @@ def should_exclude(line: str) -> bool:
return True
if line.startswith("Misc"):
values = line.split(';')
return not values[2].startswith("SignalBox")
if re.match(MISC_REGEX, line):
return True
return False