User Tools

Site Tools


manual:subwaysim:map_construction:prepare_map

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
manual:subwaysim:map_construction:prepare_map [2026/01/14 13:17] – [5.4 addSpawnPlatform()] dcsmanual:subwaysim:map_construction:prepare_map [2026/01/14 15:42] (current) – [Configuring Player Spawn Settings] dcs
Line 262: Line 262:
 ---- ----
  
-==== Finalizing Station Setup ====+===== Player Spawns (Career Mode) =====
  
-Configure all stations until the station layout matches the intended design.+For career mode, the map must define **player spawn locations**. 
 +These determine **where the player appears** when taking over a train during a career run.
  
-Repeat this process for: +Placing player spawns is quick and does not require any Lua setup at this stage.
-  * The opposite terminus +
-  * The intermediate station near the depot +
-  * The depot itself+
  
-Once Station Definitions are finished, the map is ready for: +==== Placing a Player Spawn ====
-  * AI train spawning +
-  * Timetables +
-  * Station-based routing+
  
-----+Player spawns are provided as a Blueprint inside the SDK.
  
-====== Map.lua Explained (TestMap Example) ======+Path: 
 +  SubwaySim2_Modding / GameFramework / SubwaySim2 / **BP_PlayerSpawn**
  
-This page explains the structure of a **Map.lua** file for SubwaySim 2+Drag **BP_PlayerSpawn** into your level and place it at the desired location
-It follows the file from **top to bottom** and explains each section in detail.+Rotate the actor so that the **arrow points in the direction the player should face** after spawning.
  
-The Map.lua consists of two major parts: +{{:manual:subwaysim:prepare_map:playerspawn:spawn1.png?direct&800|}}
-  * **Map Registration** (ContentManager DataTable) +
-  * **Runtime Map Logic** (Lua class based on BaseMap)+
  
-----+Typically, player spawns are placed: 
 +  * on platforms 
 +  * near stopping positions 
 +  * inside depots (optional)
  
-===== Complete Map.lua File =====+==== Configuring Player Spawn Settings ====
  
-<code lua> +After placing the actor, select it and open the **Details** panel.
--- +
--- +
--- SubwaySim2 +
--- Module TestMap.lua +
--- +
--- Map file for SDK TestMap +
--- +
--- +
--- Author: SDK User +
--- Date: __/__/____ +
--- +
----@class TestMap : TestMap, BaseMap +
-TestMap = Class("TestMap", TestMap, BaseMap);+
  
----@type SSB_Map_DataTable +The following settings are relevant:
-local TestMap_DataTable = { +
- contentType = "map", +
- contentName = "TestMap", +
- class = TestMap, +
- levelName = "Testmap", +
- author = "$GameDeveloper",+
  
- title = "SDK TestMap", +  * **Station Name**   
- subtitle = "This could be your text"+    Short station code (e.g. `DP``TS`).   
- description = "This is a test map that demonstrates how to use the Modding SDKYou can also use it for testing your own vehicles.", +    Must match the station short name used later in Map.lua.
- previewFilename = "/SubwaySim2_Core/UI/MainMenu/Backgrounds/CityBerlin.CityBerlin", +
-}; +
-g_contentManager:addContent(TestMap_DataTable);+
  
---- Creates a new instance of this class +  * **Platforms**   
----@return TestMap +    List of platform numbers for which this spawn is valid.   
-function TestMap:new() +    These platform numbers must correspond to the platforms defined in the station’s **BP_StationDefinition**.
- self = TestMap:emptyNew();+
  
- self.levelName = "Testmap"; +Using this setup, you can control **which platforms can be used as takeover points in career mode**.
- self.displayName = "SDK TestMap"; +
-  +
- -- latitude and longitude of Berlin's city center +
- self.latitude = 52.518611; +
- self.longitude = 13.408333; +
- -- UTC+1 +
- self.timezone = 1;+
  
- self:loadStations(); +{{:manual:subwaysim:prepare_map:playerspawn:spawn2.png?direct&300|}}
- self:loadTimetables(); +
- self:loadCareerMode();+
  
- EventManager.callModListeners("onMapCreated", self);+==== Important Note ====
  
- return self; +The player spawn actors only define **physical spawn locations**.
-end;+
  
---- Event to load any additionally required level instances +Actual career mode logic (such as
-function TestMap:loadLevelInstances() +  * takeover stations 
- assert(GameplayStatics.loadLevelInstance("SubwaySim2_Environment", Vector3.zero, Vector3.zero), "Failed to load a part of the level"); +  * available vehicles 
-end;+  * probabilities 
 +  * route closures)
  
---- Loads the station definitions for this map +is configured later in
-function TestMap:loadStations() +  * **Create Map.lua**
- ---@type table<string, Station> +
- self.stations = {}+
  
- self.stations.TS = Station:new("TS", "TestStation"+Do not add career logic here — only place and configure the spawn actors.
- :addSpawnPlatform("1", 115, 2) +
- :addSpawnPlatform("2", 115, 2) +
- +
- self.stations.TSD = Station:new("TSD", "TestStation Depot"+
- +
- self.stations.TSA = Station:new("TSA", "TestStation Anfang"+
- :addSpawnPlatform("1", 110, 1) +
- :addSpawnPlatform("2", 110, 1) +
- +
- self.stations.DP = Station:new("DP", "Depot"+
- :addSpawnPlatform("51", 220, 2) +
- :addSpawnPlatform("52", 220, 2) +
- :addSpawnPlatform("53", 220, 2) +
- :addSpawnPlatform("54", 220, 2) +
- :addSpawnPlatform("60", 110, 2) +
- +
-end +
- +
---- Loads the default timetables for this map +
-function TestMap:loadTimetables() +
-  +
- ---@type Timetable[] +
- self.timetables = {}; +
-  +
- -- Direction 1 (TS -> TSA) +
- self.TestLine_Dir1 = Timetable:new("U1", 0) +
- :addTrainComposition("Berlin_HK_1x", 0.5) +
- :addTrainComposition("Berlin_HK_2x"+
- :addTrainComposition("Berlin_A3L92_1x", 0) +
- :addTrainComposition("Berlin_A3L92_2x", 0) +
- :addTrainComposition("Berlin_A3L92_3x", 0.5) +
- :addTrainComposition("Berlin_A3L92_4x"+
- :addStop({ +
- station = self.stations.TS, +
- platform = 2, +
- departure = 0, +
- speedLimit = 70, +
- routeSettingMaxETA = 0.5, -- Fahrstraße stellt sich erst 0.5 Minuten vor Abfahrt +
- }) +
- :addStop({ +
- station = self.stations.TSD, +
- platform = 2, +
- departure = 0, +
- speedLimit = 70, +
- }) +
- :addStop({ +
- station = self.stations.TSA, +
- platform = 1, +
- departure = 0, +
- speedLimit = 70, +
- altPlatform = { "2",}, +
- }) +
-  +
- -- Direction 2 (TSA -> TS) +
- self.TestLine_Dir2 = Timetable:new("U1", 0) +
- :addTrainComposition("Berlin_HK_1x", 0.5) +
- :addTrainComposition("Berlin_HK_2x"+
- :addTrainComposition("Berlin_A3L92_1x", 0) +
- :addTrainComposition("Berlin_A3L92_2x", 0) +
- :addTrainComposition("Berlin_A3L92_3x", 0.5) +
- :addTrainComposition("Berlin_A3L92_4x"+
- :addStop({ +
- station = self.stations.TSA, +
- platform = 1, +
- departure = 0, +
- speedLimit = 70, +
- routeSettingMaxETA = 0.5, -- Fahrstraße stellt sich erst 0.5 Minuten vor Abfahrt +
- }) +
- :addStop({ +
- station = self.stations.TSD, +
- platform = 1, +
- departure = 0, +
- speedLimit = 70, +
- }) +
- :addStop({ +
- station = self.stations.TS, +
- platform = 2, +
- departure = 0, +
- speedLimit = 70, +
- altPlatform = { "1",}, +
- }) +
- +
- -- List of templates by line, then by direction +
- ---@type Timetable[][] +
- self.templatesByLine = { +
- [1] = { +
- [1] = self.TestLine_Dir1, +
- [2] = self.TestLine_Dir2, +
- }, +
- }; +
- +
- ---@type table<1|2, Timetable[]> +
- self.templatesByDirection = { +
- [1] = { +
- self.TestLine_Dir1, +
- }, +
- [2] = { +
- self.TestLine_Dir2, +
- }, +
- }; +
- +
- local DM = DayMask; +
- +
- -- Repeating interval example +
- TableUtil.insertList(self.timetables, self.TestLine_Dir1:clone(daytime(04, 30)):repeatUntil(daytime(23, 30), 10)); +
- TableUtil.insertList(self.timetables, self.TestLine_Dir2:clone(daytime(04, 35)):repeatUntil(daytime(23, 35), 10)); +
- +
- ---@type table<string, Depot_DepotSpace[]> +
- self.depots = { +
- }; +
- +
- ---@type table<Station, ControlCenter_DispatchingStrategy[]> +
- self.dispatchingStrategies = { +
- +
- -- Turnaround logic at TS +
-  [self.stations.TS] = { +
-+
- sourceStation = self.stations.TS, +
- targetStation = self.stations.TS, +
- sourcePlatforms = { "1", "2" }, +
- targetPlatforms = { "1", "2" }, +
- replaceFirstPlatform = true, +
- keepLine = false, +
- minLayover = 4, +
- },  +
- }, +
- +
- -- Turnaround logic at TSA +
- [self.stations.TSA] = { +
-+
- sourceStation = self.stations.TSA, +
- targetStation = self.stations.TSA, +
- sourcePlatforms = { "1", "2" }, +
- targetPlatforms = { "1", "2" }, +
- replaceFirstPlatform = true, +
- keepLine = false, +
- minLayover = 4, +
- },  +
- }, +
- }; +
-end; +
- +
---- Initializes data for career mode +
-function TestMap:loadCareerMode() +
-end; +
- +
---- Registers all valid timetables to the given `controlCenter` instance +
----@param controlCenter ControlCenter +
-function TestMap:registerTimetables(controlCenter) +
- controlCenter:setStationList(self.stations); +
- controlCenter:setTimetableList(self.timetables, self.dispatchingStrategies, self.depots); +
-end; +
-</code>+
  
 ---- ----
  
-===== 1) Map Registration (ContentManager DataTable) =====+===== Finalizing Station Setup =====
  
-The DataTable registers the map in the ContentManager.   +Configure all stations until the station layout matches the intended design.
-Without it the map will not appear in the map selection menu and cannot be loaded.+
  
-----+Repeat this process for: 
 +  * The opposite terminus 
 +  * The intermediate station near the depot 
 +  * The depot itself
  
-==== DataTable Fields ==== +Once Station Definitions are finished, the map is ready for: 
- +  * AI train spawning 
-^ Field ^ Description ^ +  * Timetables 
-| contentType | Defines the type of content. Must be `"map"`. | +  * Station-based routing
-| contentName | Unique internal identifier for this map across all mods. | +
-| class | Reference to the Lua map class that provides runtime logic. | +
-| levelName | Unreal level (.umap) name that will be loaded. Must match exactly. | +
-| author | Author metadata (UI / debugging). | +
-| title | Map title shown in the selection menu. | +
-| subtitle | Optional subtitle below the title. | +
-| description | Longer description shown in UI. | +
-| previewFilename | Path to the preview image used in the main menu. | +
- +
- +
-==== Registering the DataTable ==== +
- +
-After the table is defined, it must be registered: +
- +
-<code lua> +
-g_contentManager:addContent(TestMap_DataTable); +
-</code> +
- +
-If this call is missing, the map is not registered and will never load. +
- +
----- +
- +
-===== 2) Runtime Map Class (BaseMap) ===== +
- +
-The runtime class is responsible for everything that happens when the map is loaded+
-  * defining stations and their platforms +
-  * defining timetables and AI services +
-  * configuring dispatching / turnaround rules +
-  * optional career mode setup +
- +
- +
-==== Class Definition ==== +
- +
-<code lua> +
-TestMap = Class("TestMap", TestMap, BaseMap); +
-</code> +
- +
-This creates a new map class inheriting from `BaseMap`. +
- +
----- +
- +
-===== 3) Constructor (new) ===== +
- +
-The constructor creates the map instance and prepares the runtime data. +
- +
- +
-==== Core Properties ==== +
- +
-^ Property ^ Description ^ +
-| self.levelName | The Unreal level to load (must match DataTable `levelName`). | +
-| self.displayName | Internal display name used at runtime. | +
-| self.latitude | Used for sun position and environment lighting. | +
-| self.longitude | Used for sun position and environment lighting. | +
-| self.timezone | Timezone offset for day/time simulation (UTC+1 = 1). | +
- +
- +
-==== Loading Runtime Data ==== +
- +
-The order matters: +
- +
-  * `loadStations()` must run first (timetables reference stations) +
-  * `loadTimetables()` uses station references +
-  * `loadCareerMode()` is optional +
- +
- +
- +
-==== Mod Event Hook ==== +
- +
-<code lua> +
-EventManager.callModListeners("onMapCreated", self); +
-</code> +
- +
-This allows other mods or systems to react when the map instance is created. +
- +
----- +
- +
-===== 4) loadLevelInstances() (Optional) ===== +
- +
-Maps can optionally load additional level instances (e.g. a city environment). +
- +
- +
-==== What the Example Does ==== +
- +
-<code lua> +
-GameplayStatics.loadLevelInstance("SubwaySim2_Environment", Vector3.zero, Vector3.zero) +
-</code> +
- +
-`assert(...)` stops execution early if loading fails, which helps during development. +
- +
----- +
- +
-===== 5) Stations (Derived from BP_StationDefinition) ===== +
- +
-Stations defined in `loadStations()` must match **BP_StationDefinition** actors placed in the Unreal Editor. +
- +
- +
-==== 5.1 How Lua Stations Connect to BP_StationDefinition ==== +
- +
-The connection is made via the station short name: +
- +
-  * In Unreal: BP_StationDefinition → **Name Short** +
-  * In Lua: `Station:new("TS", "TestStation")` +
- +
-If the short name does not match exactly: +
-  * stations may not register correctly +
-  * AI routing can fail +
-  * timetable stops may not resolve +
- +
- +
-==== 5.2 Station Table ==== +
- +
-Stations are stored as a keyed table: +
- +
-<code lua> +
----@type table<string, Station> +
-self.stations = {} +
-</code> +
- +
-The key is usually identical to the short name: +
-  * `self.stations.TS` +
-  * `self.stations.TSA` +
-  * `self.stations.DP` +
- +
- +
-==== 5.3 Station:new() ==== +
- +
-Creating a station: +
- +
-<code lua> +
-Station:new("TS", "TestStation"+
-</code> +
- +
-^ Parameter ^ Description ^ +
-| `"TS"` | Short name (station code). Must match BP_StationDefinition Name Short. | +
-| `"TestStation"` | Display name shown in UI. | +
- +
- +
-==== 5.4 addSpawnPlatform() ==== +
- +
-Spawn platforms define where trains may spawn for: +
-  * AI traffic +
-  * player spawning (depending on map setup) +
- +
-Example: +
- +
-<code lua> +
-:addSpawnPlatform("1", 115, 2) +
-</code> +
- +
-^ Parameter ^ Description ^ +
-| `"1"` | Platform number as defined in BP_StationDefinition platform array. | +
-| `115` | Max allowed train length in meters for spawning at this platform. | +
-| `2` | Spawn direction on the track (orientation). Must match your platform Begin/End marker direction logic. | +
- +
-⚠️ **Important** +
-Platform numbers are not “free”. They must match exactly the platform configuration inside BP_StationDefinition. +
- +
- +
-==== 5.5 Example: Depot Platforms ==== +
- +
-The depot station `DP` uses multiple platform numbers: +
- +
-  * 51–54 +
-  * 60 +
- +
-This is a common pattern to represent multiple depot tracks. +
- +
----- +
- +
-===== 6) Timetables ===== +
- +
-Timetables define: +
-  * which trains spawn (compositions) +
-  * what route they drive (stops) +
-  * on which platforms they stop +
-  * how often services repeat +
- +
----- +
- +
-==== 6.1 Timetable:new() ==== +
- +
-A timetable template is created with: +
- +
-<code lua> +
-Timetable:new("U1", 0) +
-</code> +
- +
-^ Parameter ^ Description ^ +
-| `"U1"` | Line name used for UI and routing logic. | +
-| `0` | Variant / index value (map-specific usage). | +
- +
-Templates are usually created per direction: +
-  * Direction 1: TS → TSA +
-  * Direction 2: TSA → TS +
- +
----- +
- +
-==== 6.2 Train Compositions ==== +
- +
-(Replace with your corrected version – you already asked for that) +
- +
----- +
- +
-==== 6.3 addStop() (Route Definition) ==== +
- +
-Stops define the actual route of a timetable. +
-Each stop is a table passed into `addStop({ ... })`. +
- +
-Example: +
- +
-<code lua> +
-:addStop({ +
- station = self.stations.TS, +
- platform = 2, +
- departure = 0, +
- speedLimit = 70, +
- routeSettingMaxETA = 0.5, +
-}) +
-</code> +
- +
-^ Field ^ Type ^ Description ^ +
-| station | Station | Reference to a station defined in `loadStations()`. | +
-| platform | number | Platform number the train uses at this station. Must exist in BP_StationDefinition. | +
-| departure | number | Minutes after service start/spawn when the train departs this stop. | +
-| speedLimit | number | Speed limit applied after departing this stop (signal logic dependent). | +
-| routeSettingMaxETA | number (optional) | How many minutes before departure the route (Fahrstraße) should be requested/set. | +
-| altPlatform | table<string> (optional) | Alternative platforms that may be used if the primary platform is unavailable. | +
- +
----- +
- +
-==== 6.4 altPlatform (Alternative Platforms) ==== +
- +
-Example: +
- +
-<code lua> +
-altPlatform = { "2",+
-</code> +
- +
-⚠️ Use string values (`"1"`, `"2"`) because platform identifiers are typically handled as strings in routing/dispatch contexts. +
- +
-This allows AI to select another platform if: +
-  * the preferred platform is blocked +
-  * dispatching assigns an alternative +
- +
----- +
- +
-==== 6.5 routeSettingMaxETA (Route Pre-Setting) ==== +
- +
-Example: +
- +
-<code lua> +
-routeSettingMaxETA = 0.5 +
-</code> +
- +
-Meaning: +
-  * the route will be requested/updated roughly **0.5 minutes before departure** +
- +
-This can help avoid early route locking and improves traffic handling at busy stations. +
- +
----- +
- +
-==== 6.6 clone() + repeatUntil() (Creating Services) ==== +
- +
-A timetable template does not spawn trains by itself.   +
-It must be cloned into real timetable entries. +
- +
-Example: +
- +
-<code lua> +
-TableUtil.insertList( +
- self.timetables, +
- self.TestLine_Dir1:clone(daytime(04, 30)):repeatUntil(daytime(23, 30), 10) +
-); +
-</code> +
- +
-^ Call ^ Description ^ +
-| clone(daytime(HH, MM)) | Creates a timetable entry starting at a given time. | +
-| repeatUntil(daytime(HH, MM), interval) | Repeats the entry every X minutes until the end time. | +
-| TableUtil.insertList(list, result) | Inserts the generated entries into `self.timetables`. | +
- +
-Result: +
-  * a full day service pattern is generated automatically +
- +
----- +
- +
-==== 6.7 templatesByLine / templatesByDirection ==== +
- +
-These tables store template references for later use (UI, dispatching helpers, debugging). +
- +
-^ Table ^ Structure ^ Purpose ^ +
-| templatesByLine | Timetable[][] | Group templates by line, then direction index. | +
-| templatesByDirection | table<1|2, Timetable[]> | Quick access to templates by direction. | +
- +
----- +
- +
-===== 7) Depots and Dispatching ===== +
- +
-This section defines: +
-  * depot storage spaces (optional) +
-  * turnaround / dispatch behavior at stations +
- +
----- +
- +
-==== 7.1 Depots (self.depots) ==== +
- +
-<code lua> +
----@type table<string, Depot_DepotSpace[]> +
-self.depots = {} +
-</code> +
- +
-In this example the table is empty. +
-It can later be filled with depot spaces and rules. +
- +
----- +
- +
-==== 7.2 Dispatching Strategies (self.dispatchingStrategies) ==== +
- +
-Dispatching strategies tell the ControlCenter how trains should be handled when they reach a station: +
-  * turnaround +
-  * reuse +
-  * platform reassignment +
- +
-Structure: +
- +
-<code lua> +
----@type table<Station, ControlCenter_DispatchingStrategy[]> +
-self.dispatchingStrategies = { +
- [self.stations.TS]  = { ... }, +
- [self.stations.TSA] = { ... }, +
-+
-</code> +
- +
-Each station maps to a list of strategy entries. +
- +
----- +
- +
-==== 7.3 Dispatching Strategy Fields ==== +
- +
-Example strategy: +
- +
-<code lua> +
-+
- sourceStation = self.stations.TS, +
- targetStation = self.stations.TS, +
- sourcePlatforms = { "1", "2" }, +
- targetPlatforms = { "1", "2" }, +
- replaceFirstPlatform = true, +
- keepLine = false, +
- minLayover = 4, +
-+
-</code> +
- +
-^ Field ^ Type ^ Description ^ +
-| sourceStation | Station | Station where the train arrives. | +
-| targetStation | Station | Station where the train should be dispatched to next. For turnaround this is the same station. | +
-| sourcePlatforms | table<string> | Platforms where arriving trains are accepted. | +
-| targetPlatforms | table<string> | Platforms that may be used for the next departure. | +
-| replaceFirstPlatform | boolean | Allows the first platform of the next service to be replaced (platform reassignment). | +
-| keepLine | boolean | If true, keeps the line association. If false, line may be reset/changed by dispatch logic. | +
-| minLayover | number | Minimum layover time (minutes) before the next departure. | +
- +
----- +
- +
-===== 8) Career Mode (Optional) ===== +
- +
-`loadCareerMode()` is optional and currently empty. +
- +
-This is where career mode related data can be initialized later. +
- +
----- +
-===== 9) Registering Stations and Timetables ===== +
- +
-The final step is registering runtime data with the ControlCenter: +
- +
-<code lua> +
-controlCenter:setStationList(self.stations); +
-controlCenter:setTimetableList(self.timetables, self.dispatchingStrategies, self.depots); +
-</code> +
- +
-^ Call ^ Description ^ +
-| setStationList | Registers all stations for routing, UI and spawning logic. | +
-| setTimetableList | Registers AI services plus dispatching and depot logic. | +
- +
-If this function is missing or incomplete: +
-  * AI traffic will not work +
-  * stations may not be recognized for routing+
  
 ---- ----
Line 927: Line 353:
   * create AI timetables and services   * create AI timetables and services
   * configure dispatching and depot logic   * configure dispatching and depot logic
 +
 +At the same time, you can already continue to **visually build out and refine the map**:
 +  * place platforms and station structures
 +  * add props and environment details
 +  * further shape stations and depots using editor tools
 +
 +For this, you can use tools such as:
 +  * [[manual:subwaysim:propplacing_tool|Prop Placing Tool]]
 +
 +Both workflows – **Map.lua logic** and **visual map building** – can be developed in parallel.
  
 Continue with: Continue with:
manual/subwaysim/map_construction/prepare_map.1768393039.txt.gz · Last modified: by dcs

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki