Added SpawnPoints
+Added SpawnPoint object parser, layer and icon *Renamed Scenery.addSpawnSignal to .addSpawnPoint *Renamed Scenery.spawnSignals to .spawnPoints *Minor name changes
This commit is contained in:
parent
197cb2dcde
commit
38ecdbc2e3
8
public/assets/spawn.svg
Normal file
8
public/assets/spawn.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?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">
|
||||||
|
<path d="m33.8 15.3c-5.9209 0-10.8 4.8791-10.8 10.8v37.8c0 5.9209 4.8791 10.8 10.8 10.8h32.4c5.9209 0 10.8-4.8791 10.8-10.8v-37.8c0-5.9209-4.8791-10.8-10.8-10.8z" class="background" />
|
||||||
|
<path d="m32 12c-6.5788 0-12 5.4215-12 12v42c0 5.3408 3.5732 9.9187 8.4377 11.453l-2.2732 6.567a3 3 0 0 0 1.8552 3.8163 3 3 0 0 0 3.8163-1.8557l2.7616-7.9804h30.805l2.7631 7.9804a3 3 0 0 0 3.8163 1.8557 3 3 0 0 0 1.8536-3.8163l-2.2732-6.567c4.8645-1.5338 8.4372-6.1117 8.4372-11.453v-42c0-6.5788-5.421-12-12-12h-36zm0 8h36c2.2852 0 4.0003 1.7151 4.0003 4.0003v42c0 2.2852-1.7151 3.9998-4.0003 3.9998h-36c-2.2852 0-4.0003-1.7146-4.0003-3.9998v-42c0-2.2852 1.7151-4.0003 4.0003-4.0003z" stop-color="#000000" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="m40 54a4 4 0 0 1-4 4 4 4 0 0 1-4-4 4 4 0 0 1 4-4 4 4 0 0 1 4 4z" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"/>
|
||||||
|
<path d="m68 54a4 4 0 0 1-4 4 4 4 0 0 1-4-4 4 4 0 0 1 4-4 4 4 0 0 1 4 4z" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"/>
|
||||||
|
<path d="m34 24h32.38c1.108 0 2 0.892 2 2v12.801c0 1.108-0.892 2-2 2h-32.38c-1.108 0-2-0.892-2-2v-12.801c0-1.108 0.892-2 2-2z" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@ -17,16 +17,17 @@ export default function LocList(props) {
|
|||||||
});
|
});
|
||||||
}, [scenery?.signalBoxes]);
|
}, [scenery?.signalBoxes]);
|
||||||
|
|
||||||
const spawnSignals = useMemo(() => {
|
const spawnPoints = useMemo(() => {
|
||||||
if (!scenery?.spawnSignals) return null;
|
if (!scenery?.spawnPoints) return null;
|
||||||
return scenery.spawnSignals.map(signal => {
|
return scenery.spawnPoints.map(trackObject => {
|
||||||
const pos = signal.pos.toSVGCoords();
|
const pos = trackObject.pos.toSVGCoords();
|
||||||
const name = signal.spawn_info.name || signal.getPrintableSignalName();
|
const isSignal = trackObject.type === 'Signal';
|
||||||
|
const name = trackObject.spawn_info.name || (isSignal ? trackObject.getPrintableSignalName() : trackObject.getPrintableSpawnPointName());
|
||||||
return (
|
return (
|
||||||
<ClickableLocation name={name} pos={pos} key={signal.id} />
|
<ClickableLocation name={name} pos={pos} key={trackObject.id} />
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}, [scenery?.spawnSignals]);
|
}, [scenery?.spawnPoints]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="loclist">
|
<div className="loclist">
|
||||||
@ -34,7 +35,7 @@ export default function LocList(props) {
|
|||||||
{ signalBoxes }
|
{ signalBoxes }
|
||||||
</div>
|
</div>
|
||||||
<div className="loclist-section">
|
<div className="loclist-section">
|
||||||
{ spawnSignals }
|
{ spawnPoints }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -82,3 +82,11 @@
|
|||||||
.map svg g.derailer path {
|
.map svg g.derailer path {
|
||||||
fill: #eee;
|
fill: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.map svg g.spawn-point path {
|
||||||
|
fill: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map svg g.spawn-point path.background {
|
||||||
|
fill: #111;
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import SignRenderer from './object-renderers/SignRenderer';
|
|||||||
import NEVPRenderer from './object-renderers/NEVPRenderer';
|
import NEVPRenderer from './object-renderers/NEVPRenderer';
|
||||||
import DerailerRenderer from './object-renderers/DerailerRenderer';
|
import DerailerRenderer from './object-renderers/DerailerRenderer';
|
||||||
import ElectrificationStatusPopup from './additional-layer-components/ElectrificationStatusPopup';
|
import ElectrificationStatusPopup from './additional-layer-components/ElectrificationStatusPopup';
|
||||||
|
import SpawnPointRenderer from './object-renderers/SpawnPointRenderer';
|
||||||
|
|
||||||
const ObjectRendererQueue = [
|
const ObjectRendererQueue = [
|
||||||
{
|
{
|
||||||
@ -61,6 +62,13 @@ const ObjectRendererQueue = [
|
|||||||
'renderer': SignalRenderer,
|
'renderer': SignalRenderer,
|
||||||
'cond': (layers) => layers['signals']
|
'cond': (layers) => layers['signals']
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'name': 'spawn-points',
|
||||||
|
'category': 'track-objects',
|
||||||
|
'type': 'SpawnPoint',
|
||||||
|
'renderer': SpawnPointRenderer,
|
||||||
|
'cond': (layers) => layers['spawn-points'],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'name': 'signalboxes',
|
'name': 'signalboxes',
|
||||||
'category': 'misc',
|
'category': 'misc',
|
||||||
|
|||||||
33
src/components/map/object-renderers/SpawnPointRenderer.js
Normal file
33
src/components/map/object-renderers/SpawnPointRenderer.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { ReactSVG } from 'react-svg'
|
||||||
|
import AngleHelper from '../../../helpers/angleHelper';
|
||||||
|
|
||||||
|
export default function SpawnPointRenderer(props) {
|
||||||
|
const { object } = props;
|
||||||
|
const [x, y] = object.pos.toSVGCoords();
|
||||||
|
|
||||||
|
const rot = AngleHelper.normalizeDegAngle(object.rot.y);
|
||||||
|
const upsideDown = rot >= 180;
|
||||||
|
const upsideDownRot = upsideDown ? 90 : -90;
|
||||||
|
const anchor = upsideDown ? "start" : "end";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g className="spawn-point" transform={`translate(${x}, ${y}) rotate(${object.rot.y})`}>
|
||||||
|
<g className="signal-icon" transform={`rotate(180) translate(-2.835, -2.835)`}>
|
||||||
|
<ReactSVG
|
||||||
|
src={`${process.env.PUBLIC_URL}/assets/spawn.svg`}
|
||||||
|
wrapper='svg'
|
||||||
|
|
||||||
|
beforeInjection={(svg) => {
|
||||||
|
svg.setAttribute('width', '1.5mm');
|
||||||
|
svg.setAttribute('height', '1.5mm');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g transform={`translate(0, 3) rotate(${upsideDownRot})`}>
|
||||||
|
<text x="0" y="0" textAnchor={anchor} dominantBaseline="middle">
|
||||||
|
{object.getPrintableSpawnPointName()}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -21,7 +21,7 @@ const Constants = {
|
|||||||
switchInvalidTrackConnection: true,
|
switchInvalidTrackConnection: true,
|
||||||
unknownObjectType: true,
|
unknownObjectType: true,
|
||||||
unknownTrackType: true,
|
unknownTrackType: true,
|
||||||
signalWithoutSpawnInfo: true,
|
spawnWithoutSpawnInfo: true,
|
||||||
trackAliasAlreadyExists: true,
|
trackAliasAlreadyExists: true,
|
||||||
trackAliasNoTrack: true,
|
trackAliasNoTrack: true,
|
||||||
switchUndefinedModel: true,
|
switchUndefinedModel: true,
|
||||||
@ -50,7 +50,7 @@ const Constants = {
|
|||||||
{
|
{
|
||||||
id: 'switches-names',
|
id: 'switches-names',
|
||||||
name: 'Switches names',
|
name: 'Switches names',
|
||||||
default: true,
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'isolations-ids',
|
id: 'isolations-ids',
|
||||||
@ -67,6 +67,11 @@ const Constants = {
|
|||||||
name: 'Signals',
|
name: 'Signals',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'spawn-points',
|
||||||
|
name: 'SpawnPoints',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'derailers',
|
id: 'derailers',
|
||||||
name: 'Derailers',
|
name: 'Derailers',
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import MainCamera from './main-camera';
|
|||||||
import ElectrificationResolver from './electrification-resolver';
|
import ElectrificationResolver from './electrification-resolver';
|
||||||
import NEVP from './nevp';
|
import NEVP from './nevp';
|
||||||
import Derailer from './derailer';
|
import Derailer from './derailer';
|
||||||
|
import SpawnPoint from './spawn-point';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: add support for WorldRotation and WorldTranslation
|
TODO: add support for WorldRotation and WorldTranslation
|
||||||
@ -129,6 +130,8 @@ export default class SceneryParser {
|
|||||||
return Derailer.fromText(text);
|
return Derailer.fromText(text);
|
||||||
} else if(NEVP.isNEVP(text)) {
|
} else if(NEVP.isNEVP(text)) {
|
||||||
return NEVP.fromText(text);
|
return NEVP.fromText(text);
|
||||||
|
} else if(SpawnPoint.isSpawnPoint(text)) {
|
||||||
|
return SpawnPoint.fromText(text);
|
||||||
} else {
|
} else {
|
||||||
return TrackObject.fromText(text);
|
return TrackObject.fromText(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export default class Scenery
|
|||||||
{
|
{
|
||||||
objects = {};
|
objects = {};
|
||||||
signalBoxes = [];
|
signalBoxes = [];
|
||||||
spawnSignals = [];
|
spawnPoints = [];
|
||||||
bounds = { minX: Infinity, minZ: Infinity, maxX: -Infinity, maxZ: -Infinity };
|
bounds = { minX: Infinity, minZ: Infinity, maxX: -Infinity, maxZ: -Infinity };
|
||||||
trackAliases = {};
|
trackAliases = {};
|
||||||
electrificationResolved = ElectrificationResolutionStatus.NOT_RESOLVED;
|
electrificationResolved = ElectrificationResolutionStatus.NOT_RESOLVED;
|
||||||
@ -19,8 +19,8 @@ export default class Scenery
|
|||||||
this.signalBoxes.push(signalBox);
|
this.signalBoxes.push(signalBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSpawnSignal(signal) {
|
addSpawnPoint(trackObject) {
|
||||||
this.spawnSignals.push(signal);
|
this.spawnPoints.push(trackObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
addObject(object) {
|
addObject(object) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export default class Signal extends TrackObject {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.is_spawn && !this.spawn_info) {
|
if (this.is_spawn && !this.spawn_info) {
|
||||||
SceneryParserLog.warn('signalWithoutSpawnInfo', `Signal ${this.id} is marked as spawn but has no spawn info`);
|
SceneryParserLog.warn('spawnWithoutSpawnInfo', `Signal ${this.id} is marked as spawn but has no spawn info`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ export default class Signal extends TrackObject {
|
|||||||
this.applied = true;
|
this.applied = true;
|
||||||
|
|
||||||
if (this.is_spawn) {
|
if (this.is_spawn) {
|
||||||
scenery.addSpawnSignal(this);
|
scenery.addSpawnPoint(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
72
src/model/spawn-point.js
Normal file
72
src/model/spawn-point.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import SceneryParserLog from "./scenery-parser-log";
|
||||||
|
import SpawnInfo from "./spawn-info";
|
||||||
|
import TrackObject from "./track-object";
|
||||||
|
import Vector3 from "./vector3";
|
||||||
|
|
||||||
|
export default class SpawnPoint extends TrackObject {
|
||||||
|
is_spawn;
|
||||||
|
spawn_info;
|
||||||
|
spawn_point_name;
|
||||||
|
type = "SpawnPoint";
|
||||||
|
applied = false;
|
||||||
|
|
||||||
|
constructor(id, prefab_name, pos, rot, track_id, name, is_spawn, spawn_info, signal_name) {
|
||||||
|
super(id, prefab_name, pos, rot, track_id, name);
|
||||||
|
|
||||||
|
Object.assign(this, {
|
||||||
|
is_spawn,
|
||||||
|
spawn_info,
|
||||||
|
signal_name
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.is_spawn && !this.spawn_info) {
|
||||||
|
SceneryParserLog.warn('spawnWithoutSpawnInfo', `SpawnPoint ${this.id} is marked as spawn but has no spawn info`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrintableSpawnPointName() {
|
||||||
|
return this.spawn_point_name?.trim() || this.name?.trim() || "Spawn Point";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if a TrackObject text is a SpawnPoint.
|
||||||
|
@param {string} text - The text representation of the TrackObject.
|
||||||
|
@returns {boolean} - Returns true if the text represents a SpawnPoint, false otherwise.
|
||||||
|
@static
|
||||||
|
@memberof Signal
|
||||||
|
*/
|
||||||
|
static isSpawnPoint(text) {
|
||||||
|
const values = text.split(";");
|
||||||
|
if(values.length < 29) return false;
|
||||||
|
|
||||||
|
const prefabName = values[2];
|
||||||
|
return prefabName === "Spawn Point";
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromText(text) {
|
||||||
|
const values = text.split(";");
|
||||||
|
const signal = new SpawnPoint(
|
||||||
|
values[1], // id
|
||||||
|
values[2], // prefab_name
|
||||||
|
Vector3.fromValuesArray(values, 3), // pos
|
||||||
|
Vector3.fromValuesArray(values, 6), // rot
|
||||||
|
values[9], // track_id
|
||||||
|
values[11], // name,
|
||||||
|
values[12] === "Spawn Signal", // is_spawn
|
||||||
|
SpawnInfo.fromText(values[15]), // spawn_info
|
||||||
|
values[29]
|
||||||
|
);
|
||||||
|
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyObject(scenery) {
|
||||||
|
if(this.applied) return; // already applied
|
||||||
|
this.applied = true;
|
||||||
|
|
||||||
|
if (this.is_spawn) {
|
||||||
|
scenery.addSpawnPoint(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user