Added SignalBoxes, fixed bugs
+Added Misc objects parser +Added SignalBoxRenderer *Fixed Switch and TrackObject double apply protection *Updated scp.py to not exclude Signalboxes
This commit is contained in:
parent
0b77a5a782
commit
7f279bf35d
7
public/assets/signalbox.svg
Normal file
7
public/assets/signalbox.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="100mm" height="100mm" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path d="m4 19v62h92v-62zm8 8h76v46h-76z" color="#000000" fill-rule="evenodd"/>
|
||||
<circle cx="50" cy="50" r="6"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 279 B |
@ -46,3 +46,12 @@
|
||||
fill: #eee;
|
||||
font-size: 72mm;
|
||||
}
|
||||
|
||||
.map svg g.signalbox {
|
||||
fill: #eee;
|
||||
}
|
||||
|
||||
.map svg g.signalbox text {
|
||||
fill: #eee;
|
||||
font-size: 4px;
|
||||
}
|
||||
@ -4,6 +4,7 @@ import IsolationIdRenderer from './object-renderers/IsolationIdRenderer';
|
||||
import TrackObjectRenderer from './object-renderers/TrackObjectRenderer';
|
||||
import SignalRenderer from './object-renderers/SignalRenderer';
|
||||
import RouteRenderer from './object-renderers/RouteRenderer';
|
||||
import SignalBoxRenderer from './object-renderers/SignalBoxRenderer';
|
||||
|
||||
const ObjectRendererQueue = [
|
||||
{
|
||||
@ -38,6 +39,12 @@ const ObjectRendererQueue = [
|
||||
'renderer': SignalRenderer,
|
||||
'cond': (settings) => settings.layers['signals']
|
||||
},
|
||||
{
|
||||
'name': 'signalboxes',
|
||||
'category': 'misc',
|
||||
'renderer': SignalBoxRenderer,
|
||||
'cond': (settings) => settings.layers['signalboxes']
|
||||
},
|
||||
{
|
||||
'name': 'routes',
|
||||
'category': 'routes',
|
||||
|
||||
34
src/components/map/object-renderers/SignalBoxRenderer.js
Normal file
34
src/components/map/object-renderers/SignalBoxRenderer.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { ReactSVG } from 'react-svg';
|
||||
import AngleHelper from '../../../helpers/angleHelper';
|
||||
|
||||
export default function SignalBoxRenderer(props) {
|
||||
const { object } = props;
|
||||
if (!object.isSignalBox) return null;
|
||||
const [x, y] = object.pos.toSVGCoords();
|
||||
const text = `"${object.name}"`;
|
||||
|
||||
const rot = AngleHelper.normalizeDegAngle(object.rot.y);
|
||||
const upsideDown = rot >= 90 && rot < 270;
|
||||
const upsideDownRot = upsideDown ? 180 : 0;
|
||||
|
||||
return (
|
||||
<g className="signalbox" transform={`translate(${x}, ${y}) rotate(${object.rot.y}) `}>
|
||||
<g className="signalbox-icon" transform={`translate(-4.725, -4.725)`}>
|
||||
<ReactSVG
|
||||
src="/assets/signalbox.svg"
|
||||
wrapper='svg'
|
||||
|
||||
beforeInjection={(svg) => {
|
||||
svg.setAttribute('width', '2.5mm');
|
||||
svg.setAttribute('height', '2.5mm');
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
<g transform={`translate(0, 5) rotate(${upsideDownRot})`}>
|
||||
<text x="0" y="0" textAnchor="middle" dominantBaseline="middle">
|
||||
{text}
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
@ -36,6 +36,11 @@ const Constants = {
|
||||
name: 'Signals',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
id: 'signalboxes',
|
||||
name: 'Signal boxes',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
id: 'routes',
|
||||
name: 'Routes',
|
||||
|
||||
35
src/model/misc.js
Normal file
35
src/model/misc.js
Normal file
@ -0,0 +1,35 @@
|
||||
import SceneryObject from "./scenery-object";
|
||||
import Vector3 from "./vector3";
|
||||
|
||||
export default class Misc extends SceneryObject {
|
||||
prefab_name;
|
||||
name;
|
||||
category = "misc";
|
||||
type = "Misc";
|
||||
isSignalBox;
|
||||
|
||||
constructor(id, misc_id, prefab_name, pos, rot, name) {
|
||||
super(id, pos, rot);
|
||||
Object.assign(this, {
|
||||
misc_id,
|
||||
prefab_name,
|
||||
name,
|
||||
});
|
||||
|
||||
this.isSignalBox = prefab_name.startsWith("SignalBox");
|
||||
}
|
||||
|
||||
static fromText(id, text) {
|
||||
const values = text.split(";");
|
||||
const object = new Misc(
|
||||
id, // id
|
||||
values[1], // misc_id
|
||||
values[2], // prefab_name
|
||||
Vector3.fromValuesArray(values, 3), // pos
|
||||
Vector3.fromValuesArray(values, 6), // rot
|
||||
values[9] // name
|
||||
);
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,14 @@ import BezierTrack from './bezier-track';
|
||||
import TrackObject from './track-object';
|
||||
import Signal from './signal';
|
||||
import Route from './route';
|
||||
import Misc from './misc';
|
||||
import SceneryParserLog from './scenery-parser-log';
|
||||
|
||||
export default class Scenery
|
||||
{
|
||||
objects = {};
|
||||
bounds = { minX: Infinity, minZ: Infinity, maxX: -Infinity, maxZ: -Infinity };
|
||||
static nextMiscId = 1;
|
||||
|
||||
getBounds () {
|
||||
return { ...this.bounds };
|
||||
@ -71,6 +73,8 @@ export default class Scenery
|
||||
return Scenery._parseTrackObject(text);
|
||||
case 'Route':
|
||||
return Route.fromText(text);
|
||||
case 'Misc':
|
||||
return Misc.fromText(Scenery.nextMiscId++, text);
|
||||
case 'Empty':
|
||||
case 'EndRoute':
|
||||
return null;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import SceneryParserLog from "./scenery-parser-log";
|
||||
import SpawnInfo from "./spawn-info";
|
||||
import TrackObject from "./track-object";
|
||||
import Vector3 from "./vector3";
|
||||
@ -16,6 +17,10 @@ export default class Signal extends TrackObject {
|
||||
spawn_info: is_spawn ? spawn_info : null,
|
||||
signal_name
|
||||
});
|
||||
|
||||
if (this.is_spawn && !this.spawn_info) {
|
||||
SceneryParserLog.warn('signalWithoutSpawnInfo', `Signal ${this.id} is marked as spawn but has no spawn info`);
|
||||
}
|
||||
}
|
||||
|
||||
getPrintableSignalName() {
|
||||
|
||||
@ -47,6 +47,7 @@ export default class Switch extends SceneryObject {
|
||||
|
||||
applyObject(scenery) {
|
||||
if(this.applied) return; // already applied
|
||||
this.applied = true;
|
||||
|
||||
this.outs = Switch.getOutsFromData(this.data);
|
||||
const r = Switch.getRadiusFromModel(this.model);
|
||||
|
||||
@ -9,6 +9,7 @@ export default class TrackObject extends SceneryObject {
|
||||
category = "track-objects";
|
||||
type = "TrackObject";
|
||||
track;
|
||||
applied = false;
|
||||
|
||||
constructor(id, prefab_name, pos, rot, track_id, name) {
|
||||
super(id, pos, rot);
|
||||
@ -34,6 +35,9 @@ export default class TrackObject extends SceneryObject {
|
||||
}
|
||||
|
||||
applyObject(scenery) {
|
||||
if(this.applied) return; // already applied
|
||||
this.applied = true;
|
||||
|
||||
const track = scenery.getObject('tracks', this.track_id);
|
||||
if (!track) {
|
||||
SceneryParserLog.warn('trackObjectCannotBeApplied', `TrackObject ${this.id} cannot be applied: track ${this.track_id} not found`)
|
||||
|
||||
16
tools/scp.py
16
tools/scp.py
@ -4,19 +4,29 @@ import sys
|
||||
#
|
||||
# [ TD2 SCENERY PROCESSOR ]
|
||||
# by masuo
|
||||
# v1.2
|
||||
# v1.3
|
||||
#
|
||||
|
||||
BAD_WORDS = ['Misc', 'Fence', 'TerrainPoint', 'Wires']
|
||||
BAD_WORDS = ['Empty,Empty', 'Forest Start,Forest Start', 'EndMiscGroup', 'Fence', 'TerrainPoint', 'Wires']
|
||||
|
||||
def should_exclude(line: str) -> bool:
|
||||
return any(bad_word in line for bad_word in BAD_WORDS)
|
||||
for word in BAD_WORDS:
|
||||
if line.startswith(word):
|
||||
return True
|
||||
|
||||
if line.startswith("Misc"):
|
||||
values = line.split(';')
|
||||
return len(values[9].strip()) == 0 or not values[2].startswith("SignalBox")
|
||||
|
||||
def process_file(file_path: str):
|
||||
if not file_path.endswith(".sc"):
|
||||
print(f"Skipping non-.sc file: {file_path}")
|
||||
return
|
||||
|
||||
if file_path.endswith(".lite.sc"):
|
||||
print(f"Skipping already processed file: {file_path}")
|
||||
return
|
||||
|
||||
output_path = file_path[:-3] + ".lite.sc"
|
||||
print(f"Processing file: {file_path} -> {output_path}")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user