aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.build.yml29
-rw-r--r--.dir-locals.el5
-rw-r--r--.gitignore1
-rw-r--r--README.md108
-rw-r--r--advtrains/api_doc.txt14
-rw-r--r--advtrains/atc.lua29
-rw-r--r--advtrains/couple.lua556
-rw-r--r--advtrains/doc/advtrains_speed_lessp.3advtrains.md15
-rw-r--r--advtrains/doc/advtrains_speed_set_restriction.3advtrains.md18
-rw-r--r--advtrains/doc/signal_aspect.7advtrains.md24
-rw-r--r--advtrains/formspec.lua111
-rw-r--r--advtrains/init.lua26
-rw-r--r--advtrains/locale/advtrains.de.tr5
-rw-r--r--advtrains/lzb.lua13
-rw-r--r--advtrains/nodedb.lua2
-rw-r--r--advtrains/path.lua39
-rw-r--r--advtrains/settingtypes.txt5
-rw-r--r--advtrains/signals.lua4
-rw-r--r--advtrains/spec/speed_spec.lua70
-rw-r--r--advtrains/speed.lua88
-rw-r--r--advtrains/trainhud.lua2
-rw-r--r--advtrains/trainlogic.lua463
-rw-r--r--advtrains/wagons.lua170
-rw-r--r--advtrains_interlocking/README.md85
-rw-r--r--advtrains_interlocking/approach.lua9
-rw-r--r--advtrains_interlocking/ars.lua4
-rw-r--r--advtrains_interlocking/aspect.lua296
-rw-r--r--advtrains_interlocking/database.lua32
-rw-r--r--advtrains_interlocking/demosignals.lua6
-rw-r--r--advtrains_interlocking/distant.lua200
-rw-r--r--advtrains_interlocking/distant_signals.lua83
-rw-r--r--advtrains_interlocking/distant_ui.lua141
-rw-r--r--advtrains_interlocking/init.lua11
-rw-r--r--advtrains_interlocking/routesetting.lua50
-rw-r--r--advtrains_interlocking/signal_api.lua446
-rw-r--r--advtrains_interlocking/signal_aspect_accessors.lua163
-rw-r--r--advtrains_interlocking/signal_aspect_ui.lua262
-rw-r--r--advtrains_interlocking/spec/ars_spec.lua67
-rw-r--r--advtrains_interlocking/spec/basic_signalling_spec.lua106
l---------advtrains_interlocking/spec/fixtures/advtrains_helpers.lua1
-rw-r--r--advtrains_interlocking/spec/mineunit.conf0
-rw-r--r--advtrains_interlocking/spec/signal_group_spec.lua95
-rwxr-xr-xadvtrains_interlocking/tcb_ts_ui.lua66
-rw-r--r--advtrains_interlocking/train_sections.lua7
-rw-r--r--advtrains_luaautomation/README.md36
-rw-r--r--advtrains_luaautomation/active_common.lua18
-rwxr-xr-x[-rw-r--r--]advtrains_luaautomation/atc_rail.lua41
-rw-r--r--advtrains_luaautomation/environment.lua11
-rw-r--r--advtrains_luaautomation/init.lua5
-rw-r--r--advtrains_luaautomation/mesecon_controller.lua259
-rwxr-xr-x[-rw-r--r--]advtrains_luaautomation/operation_panel.lua6
-rw-r--r--advtrains_luaautomation/pcnaming.lua7
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_LED_A.pngbin0 -> 2196 bytes
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_LED_B.pngbin0 -> 2188 bytes
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_LED_C.pngbin0 -> 2191 bytes
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_LED_D.pngbin0 -> 2200 bytes
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_bottom.pngbin0 -> 222 bytes
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_sides.pngbin0 -> 504 bytes
-rw-r--r--advtrains_luaautomation/textures/atlatc_luacontroller_top.pngbin0 -> 8440 bytes
-rw-r--r--advtrains_signals_japan/.gitignore1
-rw-r--r--advtrains_signals_japan/init.lua439
-rw-r--r--advtrains_signals_japan/textures/advtrains_signals_japan_mast.pngbin0 -> 180 bytes
-rw-r--r--advtrains_signals_ks/doc/advtrains_signals_ks.7advtrains.md52
-rwxr-xr-xadvtrains_signals_ks/init.lua131
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr0.obj212
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr30.obj213
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr45.obj213
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr60.obj213
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr0.obj148
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr30.obj151
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr45.obj151
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr60.obj151
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr0.obj227
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr30.obj228
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr45.obj228
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr60.obj228
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr0.obj128
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr30.obj129
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr45.obj129
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr60.obj129
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr0.obj524
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr30.obj524
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr45.obj524
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr60.obj524
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr0.obj76
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr30.obj34
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr45.obj40
-rw-r--r--advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr60.obj34
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_mast.pngbin224 -> 180 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_12.pngbin197 -> 129 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_16.pngbin190 -> 122 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_20.pngbin0 -> 5715 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_4.pngbin0 -> 113 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_6.pngbin0 -> 120 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_8.pngbin174 -> 106 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_e.pngbin166 -> 98 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_hfs.pngbin22255 -> 11564 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_lf7.pngbin0 -> 102 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x1.pngbin0 -> 77 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x2.pngbin0 -> 83 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x3.pngbin0 -> 80 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x4.pngbin0 -> 78 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x5.pngbin0 -> 75 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne4.pngbin0 -> 99 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_off.pngbin0 -> 72 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.pngbin211 -> 155 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_sign_zs10.pngbin0 -> 95 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_zs3_12.pngbin292 -> 0 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_zs3_16.pngbin318 -> 0 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_zs3_4.pngbin188 -> 0 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_zs3_6.pngbin311 -> 0 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_zs3_8.pngbin315 -> 0 bytes
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_zs3_off.pngbin82 -> 0 bytes
-rwxr-xr-xadvtrains_train_track/init.lua147
-rw-r--r--atc_command.txt4
-rw-r--r--modpack.conf1
-rw-r--r--readme.txt47
-rw-r--r--serialize_lib/spec/serialize_spec.lua (renamed from serialize_lib/tests/serialize_spec.lua)11
118 files changed, 7987 insertions, 2314 deletions
diff --git a/.build.yml b/.build.yml
new file mode 100644
index 0000000..54768a9
--- /dev/null
+++ b/.build.yml
@@ -0,0 +1,29 @@
+image: debian/stable
+packages:
+- git
+- lua5.1
+- luarocks
+sources :
+- https://git.sr.ht/~gpcf/advtrains
+
+artifacts:
+- advtrains.luacov.report.out
+- advtrains_interlocking.luacov.report.out
+
+tasks:
+
+- install_mineunit : |
+ for i in {busted,luacov}; do
+ luarocks install --local --lua-version 5.1 $i >/dev/null
+ done
+ luarocks install --local --lua-version 5.1 --server=https://luarocks.org/dev mineunit
+- run_unit_tests : |
+ cd advtrains/serialize_lib
+ ~/.luarocks/bin/busted
+ for i in {advtrains,advtrains_interlocking}; do
+ cd ../$i
+ ~/.luarocks/bin/mineunit -c
+ ~/.luarocks/bin/mineunit -r
+ sed -n '/^File/,$p' luacov.report.out
+ mv luacov.report.out ~/$i.luacov.report.out
+ done
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..57aae07
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,5 @@
+((nil (tab-width . 8))
+ (lua-mode (indent-tabs-mode . t)
+ (lua-indent-level . 8)
+ (lua-indent-close-paren-align . nil)
+ (lua-indent-nested-block-content-align . nil)))
diff --git a/.gitignore b/.gitignore
index b3180de..bef77f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
## Eclipse project files & directories
.project
.settings
+luacov.*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e80e4b5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,108 @@
+
+# ADVTRAINS – realistic trains in Minetest!
+by orwell96 and contributors (see below)
+
+[![builds.sr.ht status](https://builds.sr.ht/~gpcf/advtrains/commits/.build.yml.svg)](https://builds.sr.ht/~gpcf/advtrains/commits/.build.yml?)
+
+For up-to-date information, visit <https://advtrains.de/>
+
+License of code: GNU AGPL version 3
+License of media: CC-BY-SA 3.0
+
+(up to commit 1bb1d8 (2020-02-14), the license has been LGPL 2.1)
+
+## Installation
+
+To use advtrains, you need to install a mod providing trains. *Note
+that advtrains no longer comes bundled with any trains out of the
+box*. Some selected train mods by the authors of advtrains are:
+
+* [Basic trains](https://git.bananach.space/basic_trains.git/) by
+ orwell96, mbblp et al. The classic selection of trains for
+ advtrains, formerly included in the mod.
+* [Moretrains](https://git.bananach.space/moretrains.git) by rbduck,
+ with improvements by gpcf and Marnack.
+* [dlxtrains](https://github.com/Marnack/dlxtrains_modpack) by Marnack
+
+
+Further information is available on the [wiki](https://advtrains.de/wiki/).
+
+
+## How to contribute
+
+* [Bug tracker](https://bugs.linux-forks.de/advtrains)
+* [Discussion and Support mailing list][srht-discuss]
+* Send patches via [git-send-email][gsm] to the [dev mailing
+ list][srht-devel]
+
+
+
+[srht-discuss]: https://lists.sr.ht/~gpcf/advtrains-discuss
+[srht-devel]: https://lists.sr.ht/~gpcf/advtrains-devel
+[gsm]: https://git-send-email.io/
+
+
+## Credits
+
+### Coding
+
+Various features and bugfixes have been contributed by:
+
+- gpcf
+- Blockhead
+- ywang
+
+Small code contributions:
+
+- hlqkj
+- Maverick2797
+- AntumDeluge
+- lemon-melon
+- mbblp
+- Andrey K
+- Hume2
+- Linus Jahn
+- Pedro Gimeno
+- Relatio
+- Thomas Rudin
+- h-v-smacker
+- imcasper
+- rubenwardy
+- techniX
+
+
+
+### Assets:
+
+* Gravel Texture : from Minetest Game
+* Initial rail model/texture : DS-minetest
+* Models for signals/bumpers : mbb
+* Steam engine / wagon texture: mbb
+* Detailed Steam engine : mbb / Krokoschlange(animation)
+* Industrial engine/wagons : mbb
+* Inventory images : mbb
+* Node texture for LuaATC controller: Jeija (from Mesecons)
+* Mod Description : hajo
+* 45 degree platforms design : Och_Noe
+
+#### Sounds:
+
+* advtrains\_crossing\_bell : Codesound
+* advtrains\_japan\_horn : Codesound
+* advtrains\_steam\_whistle : googol
+* advtrains\_subway\_horn : https://freesound.org/people/Mullumbimby/sounds/385283/
+* advtrains\_subway\_\* : Gabriel (gbl08ma)
+
+
+### Testers:
+
+* gpcf (Linuxforks server)
+* imcasper (tss Branch)
+* Cato (C&C Servers)
+
+
+If I forgot someone please punish me for that. Also see the Git commit
+log.
+
+You can see this mod in action on various minetest servers, including
+the Linuxforks minetest server.
diff --git a/advtrains/api_doc.txt b/advtrains/api_doc.txt
index 8ac4986..5668ba3 100644
--- a/advtrains/api_doc.txt
+++ b/advtrains/api_doc.txt
@@ -75,9 +75,23 @@ advtrains.register_wagon(name, prototype, description, inventory_image)
^- Getting on by walking in then takes effect.
^- Positive values mean front, negative ones back. Resulting position is automatically shifted to the right side.
+ coupler_types_front = {scharfenberg=true},
+ coupler_types_back = {chain=true},
+ ^- Defines the available coupler types on this wagon on the front and back side. Wagon will only couple to wagons that have a matching coupler. (this property does not have any visual impact)
+ ^- Default: not given (nil) - causes the wagon to couple to any other wagon regardless of coupler type.
+ ^- Empty table ({}): This wagon does not couple to any other wagon (e.g. for Linetrack vehicles)
+ ^- Register coupler types using ''advtrains.register_coupler_type(type, name)''. advtrains defines the default types "chain" (Buffer and Chain) and "scharfenberg" (Scharfenberg coupler).
+
wagon_span=2,
^- How far this wagon extends from its base position. Is the half of the wagon length.
^- Used to determine in which distance the other wagons have to be positioned. Will require tweaking.
+ wheel_positions = {1.5, -1.5},
+ ^- Optional: if defined, the wagon will be placed so that these 2 wheel positions are on the track
+ ^- This parameter is recommended for long wagons (wagon_span >= 2).
+ ^- The position is a distance relative to the center of the wagon.
+ ^- Must have exactly 2 entries, corresponding to the front (1) and rear (2) wheel of the wagon object. 1st must be greater than 2nd.
+ ^- If not provided, the simple 1-position positioning logic will be used (wagon is positioned with the center on the track)
+
extent_h = 1,
^- Determines the collision box extent in x/z direction. Defaults to 1 (=3x3)
^- The actual bounding box size is (extent_h*2)+1, so 0 means 1x1, 1 means 3x3 and 2 means 5x5
diff --git a/advtrains/atc.lua b/advtrains/atc.lua
index 64cdcec..c1ff218 100644
--- a/advtrains/atc.lua
+++ b/advtrains/atc.lua
@@ -93,6 +93,7 @@ function atc.train_reset_command(train, keep_tarvel)
train.atc_delay=nil
train.atc_brake_target=nil
train.atc_wait_finish=nil
+ train.atc_wait_autocouple=nil
train.atc_arrow=nil
if not keep_tarvel then
train.tarvelocity=nil
@@ -199,10 +200,16 @@ local matchptn={
return #match+1
end,
["B([0-9]+)"]=function(id, train, match)
- if train.velocity>tonumber(match) then
- train.atc_brake_target=tonumber(match)
- if not train.tarvelocity or train.tarvelocity>train.atc_brake_target then
- train.tarvelocity=train.atc_brake_target
+ local btar = tonumber(match)
+ if train.velocity>btar then
+ train.atc_brake_target=btar
+ if not train.tarvelocity or train.tarvelocity>btar then
+ train.tarvelocity=btar
+ end
+ else
+ -- independent of brake target, must make sure that tarvelocity is not greater than it
+ if train.tarvelocity and train.tarvelocity>btar then
+ train.tarvelocity=btar
end
end
return #match+1
@@ -267,6 +274,10 @@ local matchptn={
advtrains.interlocking.ars_set_disable(train, match=="0")
return 2
end,
+ ["Cpl"]=function(id, train)
+ train.atc_wait_autocouple=true
+ return 3
+ end,
}
eval_conditional = function(command, arrow, speed)
@@ -358,11 +369,13 @@ function atc.execute_atc_command(id, train)
local match=string.match(command, "^"..pattern)
if match then
local patlen=func(id, train, match)
-
- atprint("Executing: "..string.sub(command, 1, patlen))
-
+ --atdebug("Executing: "..string.sub(command, 1, patlen))
+ --atdebug("Train ATC State: tvel=",train.tarvelocity,"brktar=",train.atc_brake_target,"delay=",train.atc_delay,"wfinish=",train.atc_wait_finish,"wacpl=",train.atc_wait_autocouple)
+
train.atc_command=string.sub(command, patlen+1)
- if train.atc_delay<=0 and not train.atc_wait_finish then
+ if train.atc_delay<=0
+ and not train.atc_wait_finish
+ and not train.atc_wait_autocouple then
--continue (recursive, cmds shouldn't get too long, and it's a end-recursion.)
atc.execute_atc_command(id, train)
end
diff --git a/advtrains/couple.lua b/advtrains/couple.lua
index 3dc336f..3e6c432 100644
--- a/advtrains/couple.lua
+++ b/advtrains/couple.lua
@@ -1,14 +1,398 @@
--couple.lua
---defines couple entities.
+--Handles coupling and discoupling of trains, and defines the coupling entities
+--Rework June 2021 - some functions from trainlogic.lua have been moved here
---advtrains:discouple
---set into existing trains to split them when punched.
---they are attached to the wagons.
---[[fields
-wagon
+-- COUPLING --
+-- During coupling rework, the behavior of coupling was changed to make automation easier. It is now as follows:
+-- Coupling is only ever initiated when a train is standing somewhere (not moving) and another train drives onto one of its ends
+-- with a speed greater than 0
+-- "stationary" train is the one standing there - in old code called "train2"
+-- "initiating" train is the one that approached it and bumped into it - typically an engine - in old code called "train1"
+-- When the initiating train has autocouple set, trains are immediately coupled
+-- When not, a couple entity is spawned and coupling commences on click
+-- Coupling MUST preserve the train ID of the initiating train, so it is done like this:
+ -- index of initiating train is set so that it matches the front pos of stationary train
+ -- remove stationary train
+ -- wagons of stationary train are inserted at the beginning of initiating train (considers direction of stat_train and inserts reverse if required)
-wagons keep their couple entity minetest-internal id inside the field discouple_id. if it refers to nowhere, they will spawn a new one if player is near
-]]
+-- train.couple_* contain references to ObjectRefs of couple objects, which contain all relevant information
+-- These objectRefs will delete themselves once the couples no longer match (see below)
+
+advtrains.coupler_types = {}
+
+function advtrains.register_coupler_type(code, name)
+ advtrains.coupler_types[code] = name
+end
+
+-- Register some default couplers
+advtrains.register_coupler_type("chain", attrans("Buffer and Chain Coupler"))
+advtrains.register_coupler_type("scharfenberg", attrans("Scharfenberg Coupler"))
+
+
+local function create_couple_entity(pos, train1, t1_is_front, train2, t2_is_front)
+ local id1 = train1.id
+ local id2 = train2.id
+
+ -- delete previous couple entities
+ if t1_is_front then
+ if train1.cpl_front then train1.cpl_front:remove() end
+ else
+ if train1.cpl_back then train1.cpl_back:remove() end
+ end
+ if t2_is_front then
+ if train2.cpl_front then train2.cpl_front:remove() end
+ else
+ if train2.cpl_back then train2.cpl_back:remove() end
+ end
+
+ local obj=minetest.add_entity(pos, "advtrains:couple")
+ if not obj then error("Failed creating couple object!") return end
+ local le=obj:get_luaentity()
+ le.train_id_1=id1
+ le.t1_is_front=t1_is_front
+ le.train_id_2=id2
+ le.t2_is_front=t2_is_front
+ --atdebug("created couple between",train1.id,train2.id,t2_is_front)
+
+ if t1_is_front then
+ train1.cpl_front = obj
+ else
+ train2.cpl_back = obj
+ end
+ if t2_is_front then
+ train2.cpl_front = obj
+ else
+ train2.cpl_back = obj
+ end
+end
+
+-- Old static couple checking. Never used for autocouple, only used for standing trains if train did not approach
+local CPL_CHK_DST = -1
+local CPL_ZONE = 2
+function advtrains.train_check_couples(train)
+ --atdebug("rechecking couples")
+ if train.cpl_front then
+ if not train.cpl_front:get_yaw() then
+ -- objectref is no longer valid. reset.
+ train.cpl_front = nil
+ end
+ end
+ if not train.cpl_front then
+ -- recheck front couple
+ local front_trains, pos = advtrains.occ.get_occupations(train, atround(train.index) + CPL_CHK_DST)
+ if advtrains.is_node_loaded(pos) then -- if the position is loaded...
+ for tid, idx in pairs(front_trains) do
+ local other_train = advtrains.trains[tid]
+ if not advtrains.train_ensure_init(tid, other_train) then
+ atwarn("Train",tid,"is not initialized! Couldn't check couples!")
+ return
+ end
+ --atdebug(train.id,"front: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
+ if other_train.velocity == 0 then
+ if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
+ create_couple_entity(pos, train, true, other_train, true)
+ break
+ end
+ if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
+ create_couple_entity(pos, train, true, other_train, false)
+ break
+ end
+ end
+ end
+ end
+ end
+ if train.cpl_back then
+ if not train.cpl_back:get_yaw() then
+ -- objectref is no longer valid. reset.
+ train.cpl_back = nil
+ end
+ end
+ if not train.cpl_back then
+ -- recheck back couple
+ local back_trains, pos = advtrains.occ.get_occupations(train, atround(train.end_index) - CPL_CHK_DST)
+ if advtrains.is_node_loaded(pos) then -- if the position is loaded...
+ for tid, idx in pairs(back_trains) do
+ local other_train = advtrains.trains[tid]
+ if not advtrains.train_ensure_init(tid, other_train) then
+ atwarn("Train",tid,"is not initialized! Couldn't check couples!")
+ return
+ end
+ --atdebug(train.id,"back: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
+ if other_train.velocity == 0 then
+ if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
+ create_couple_entity(pos, train, false, other_train, true)
+ break
+ end
+ if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
+ create_couple_entity(pos, train, false, other_train, false)
+ break
+ end
+ end
+ end
+ end
+ end
+end
+
+-- Deletes couple entities from the train
+function advtrains.couple_invalidate(train)
+ if train.cpl_back then
+ train.cpl_back:remove()
+ train.cpl_back = nil
+ end
+ if train.cpl_front then
+ train.cpl_front:remove()
+ train.cpl_front = nil
+ end
+ train.couples_up_to_date = nil
+end
+
+-- Called from train_step_b() when the current train (init_train) just stopped at one of the end indices of another train (stat_train)
+-- Depending on autocouple, either couples immediately or spawns a couple entity
+function advtrains.couple_initiate_with(init_train, stat_train, stat_is_front)
+ --atdebug("Couple init autocouple=",init_train.autocouple,"atc_w_acpl=",init_train.atc_wait_autocouple)
+ if init_train.autocouple or init_train.atc_wait_autocouple then
+ local cplmatch, msg = advtrains.check_matching_coupler_types(init_train, true, stat_train, stat_is_front)
+ if cplmatch then
+ advtrains.couple_trains(init_train, false, stat_train, stat_is_front)
+ -- clear atc couple waiting blocker
+ init_train.atc_wait_autocouple = nil
+ return
+ end
+ end
+ -- get here if either autocouple is not on or couples dont match
+ local pos = advtrains.path_get_interpolated(init_train, init_train.index)
+ create_couple_entity(pos, init_train, true, stat_train, stat_is_front)
+ -- clear ATC command on collision
+ advtrains.atc.train_reset_command(init_train)
+
+end
+
+-- check if the player has permission for the first/last wagon of the train
+local function check_twagon_owner(train, b_first, pname)
+ local wtp = b_first and 1 or #train.trainparts
+ local wid = train.trainparts[wtp]
+ local wdata = advtrains.wagons[wid]
+ if wdata then
+ return advtrains.check_driving_couple_protection(pname, wdata.owner, wdata.whitelist)
+ end
+ return false
+end
+
+-- Perform coupling, but check if the player is authorized to couple
+function advtrains.safe_couple_trains(train1, t1_is_front, train2, t2_is_front, pname)
+
+ if pname and not minetest.check_player_privs(pname, "train_operator") then
+ minetest.chat_send_player(pname, "Missing train_operator privilege")
+ return false
+ end
+
+ local wck_t1, wck_t2
+ if pname then
+ wck_t1 = check_twagon_owner(train1, t1_is_front, pname)
+ wck_t2 = check_twagon_owner(train2, t2_is_front, pname)
+ end
+ if (wck_t1 or wck_t2) or not pname then
+
+ local cplmatch, msg = advtrains.check_matching_coupler_types(train1, t1_is_front, train2, t2_is_front)
+ if cplmatch then
+ advtrains.couple_trains(train1, not t1_is_front, train2, t2_is_front)
+ else
+ minetest.chat_send_player(pname, msg)
+ end
+ end
+end
+
+-- Actually performs the train coupling. Always retains train ID of train1
+function advtrains.couple_trains(init_train, invert_init_train, stat_train, stat_train_opposite)
+ --atdebug("Couple trains init=",init_train.id,"initinv=",invert_init_train,"stat=",stat_train.id,"statreverse=",stat_train_opposite)
+
+ if not advtrains.train_ensure_init(init_train.id, init_train) then
+ atwarn("Coupling: initiating train",init_train.id,"is not initialized! Operation aborted!")
+ return
+ end
+ if not advtrains.train_ensure_init(stat_train.id, stat_train) then
+ atwarn("Coupling: stationary train",stat_train.id,"is not initialized! Operation aborted!")
+ return
+ end
+
+ -- only used with the couple entity
+ if invert_init_train then
+ advtrains.invert_train(init_train.id)
+ end
+
+ local itp = init_train.trainparts
+ local init_wagoncnt = #itp
+ local stp = stat_train.trainparts
+ local stat_wagoncnt = #stp
+ local stat_trainlen = stat_train.trainlen -- save the train length of stat train, to be added to index
+
+ if stat_train_opposite then
+ -- insert wagons in inverse order and set their wagon_flipped state
+ for i=1,stat_wagoncnt do
+ table.insert(itp, 1, stp[i])
+ local wdata = advtrains.wagons[stp[i]]
+ if wdata then
+ wdata.wagon_flipped = not wdata.wagon_flipped
+ else
+ atwarn("While coupling, wagon",stp[i],"of stationary train",stat_train.id,"not found!")
+ end
+ end
+ else
+ --insert wagons in normal order
+ for i=stat_wagoncnt,1,-1 do
+ table.insert(itp, 1, stp[i])
+ end
+ end
+
+ -- TODO: migrate some of the properties from stat_train to init_train?
+
+ advtrains.remove_train(stat_train.id)
+
+ -- Set train index forward
+ init_train.index = advtrains.path_get_index_by_offset(init_train, init_train.index, stat_trainlen)
+
+ advtrains.update_trainpart_properties(init_train.id)
+ advtrains.update_train_start_and_end(init_train)
+
+ advtrains.couple_invalidate(init_train)
+ return true
+end
+
+-- Couple types matching check
+-- returns: true, nil if OK
+-- false, errmsg if there is an error
+function advtrains.check_matching_coupler_types(t1, t1_front, t2, t2_front)
+ -- 1. get wagons
+ local t1_wid
+ if t1_front then
+ t1_wid = t1.trainparts[1]
+ else
+ t1_wid = t1.trainparts[#t1.trainparts]
+ end
+ local t2_wid
+ if t2_front then
+ t2_wid = t2.trainparts[1]
+ else
+ t2_wid = t2.trainparts[#t2.trainparts]
+ end
+
+ --atdebug("CMCT: t1_wid",t1_wid,"t2_wid",t2_wid,"")
+
+ if not t1_wid or not t2_wid then
+ return false, "Unable to retrieve wagons from train"--note: no translation needed, case should not occur
+ end
+
+ local t1_wagon = advtrains.wagons[t1_wid]
+ local t2_wagon = advtrains.wagons[t2_wid]
+
+ if not t1_wagon or not t2_wagon then
+ return false, "At least one of wagons "..t1_wagon.." or "..t2_wagon.." does not exist"--note: no translation needed, case should not occur
+ end
+
+ -- these calls do not fail, they may return placeholder - doesn't matter
+ local _,t1_wpro = advtrains.get_wagon_prototype(t1_wagon)
+ local _,t2_wpro = advtrains.get_wagon_prototype(t2_wagon)
+
+ -- get correct couplers table (front/back)
+ local t1_cplt
+ if not t1_front == not t1_wagon.wagon_flipped then --fancy XOR
+ t1_cplt = t1_wpro.coupler_types_back
+ else
+ t1_cplt = t1_wpro.coupler_types_front
+ end
+ local t2_cplt
+ if not t2_front == not t2_wagon.wagon_flipped then --fancy XOR
+ t2_cplt = t2_wpro.coupler_types_back
+ else
+ t2_cplt = t2_wpro.coupler_types_front
+ end
+
+ --atdebug("CMCT: t1",t1_cplt,"t2",t2_cplt,"")
+
+ -- if at least one of the trains has no couplers table, it always couples (fallback behavior and mode for universal shunters)
+ if not t1_cplt or not t2_cplt then
+ return true
+ end
+
+ -- have common coupler?
+ for typ,_ in pairs(t1_cplt) do
+ if t2_cplt[typ] then
+ --atdebug("CMCT: Matching type",typ)
+ return true
+ end
+ end
+ --no match, give user an info
+ local t1_cplhr, t2_cplhr = {},{}
+ for typ,_ in pairs(t1_cplt) do
+ table.insert(t1_cplhr, advtrains.coupler_types[typ] or typ)
+ end
+ if #t1_cplhr==0 then t1_cplhr[1]=attrans("<none>") end
+ for typ,_ in pairs(t2_cplt) do
+ table.insert(t2_cplhr, advtrains.coupler_types[typ] or typ)
+ end
+ if #t2_cplhr==0 then t2_cplhr[1]=attrans("<none>") end
+ return false, attrans("Can not couple: The couplers of the trains do not match (@1 and @2).", table.concat(t1_cplhr, ","), table.concat(t2_cplhr, ","))
+end
+
+-- DECOUPLING --
+function advtrains.split_train_at_fc(train, count_empty, length_limit)
+ -- splits train at first different current FC by convention,
+ -- locomotives have empty FC so are ignored
+ -- count_empty is used to split off locomotives
+ -- length_limit limits the length of the first train to length_limit wagons
+ local train_id = train.id
+ local fc = false
+ local ind = 0
+ for i = 1, #train.trainparts do
+ local w_id = train.trainparts[i]
+ local data = advtrains.wagons[w_id]
+ if length_limit and i > length_limit then
+ ind = i
+ break
+ end
+ if data then
+ local wfc = advtrains.get_cur_fc(data)
+ if wfc ~= "" or count_empty then
+ if fc then
+ if fc ~= wfc then
+ ind = i
+ break
+ end
+ else
+ fc = wfc
+ end
+ end
+ end
+ end
+ if ind > 0 then
+ return advtrains.split_train_at_index(train, ind), fc
+ end
+ if fc then
+ return nil, fc
+ end
+end
+
+function advtrains.train_step_fc(train)
+ for i=1,#train.trainparts do
+ local w_id = train.trainparts[i]
+ local data = advtrains.wagons[w_id]
+ if data then
+ advtrains.step_fc(data)
+ end
+ end
+end
+
+
+-- split_train_at_index() is in trainlogic.lua because it needs access to two local functions
+
+function advtrains.split_train_at_wagon(wagon_id)
+ --get train
+ local data = advtrains.wagons[wagon_id]
+ advtrains.split_train_at_index(advtrains.trains[data.train_id], data.pos_in_trainparts)
+end
+
+
+-- COUPLE ENTITIES --
local couple_max_dist=3
@@ -36,8 +420,6 @@ minetest.register_entity("advtrains:discouple", {
if pname and pname~="" and self.wagon then
if advtrains.safe_decouple_wagon(self.wagon.id, pname) then
self.object:remove()
- else
- minetest.add_entity(self.object:getpos(), "advtrains:lockmarker")
end
end
end,
@@ -60,10 +442,6 @@ minetest.register_entity("advtrains:discouple", {
-- advtrains:couple
-- Couple entity
-local function lockmarker(obj)
- minetest.add_entity(obj:get_pos(), "advtrains:lockmarker")
- obj:remove()
-end
minetest.register_entity("advtrains:couple", {
visual="sprite",
@@ -75,107 +453,71 @@ minetest.register_entity("advtrains:couple", {
is_couple=true,
static_save = false,
on_activate=function(self, staticdata)
- if staticdata=="COUPLE" then
- --couple entities have no right to exist further...
- atprint("Couple loaded from staticdata, destroying")
- self.object:remove()
- return
- end
- self.object:set_armor_groups({immmortal=1})
+ if staticdata=="COUPLE" then
+ --couple entities have no right to exist further...
+ --atdebug("Couple loaded from staticdata, destroying")
+ self.object:remove()
+ return
+ end
+ self.object:set_armor_groups({immmortal=1})
end,
get_staticdata=function(self) return "COUPLE" end,
on_rightclick=function(self, clicker)
- if not self.train_id_1 or not self.train_id_2 then return end
-
- local pname=clicker
- if type(clicker)~="string" then pname=clicker:get_player_name() end
-
- if advtrains.safe_couple_trains(self.train_id_1, self.train_id_2, self.t1_is_front, self.t2_is_front, pname) then
- self.object:remove()
- else
- lockmarker(self.object)
- end
+ if not self.train_id_1 or not self.train_id_2 then return end
+
+ local pname=clicker
+ if type(clicker)~="string" then pname=clicker:get_player_name() end
+
+ local train1=advtrains.trains[self.train_id_1]
+ local train2=advtrains.trains[self.train_id_2]
+
+ advtrains.safe_couple_trains(train1, self.t1_is_front, train2, self.t2_is_front, pname)
+ self.object:remove()
end,
on_step=function(self, dtime)
- if advtrains.wagon_outside_range(self.object:getpos()) then
- self.object:remove()
- return
- end
+ if advtrains.wagon_outside_range(self.object:getpos()) then
+ --atdebug("Couple Removing outside range")
+ self.object:remove()
+ return
+ end
- if not self.train_id_1 or not self.train_id_2 then atprint("Couple: train ids not set!") self.object:remove() return end
- local train1=advtrains.trains[self.train_id_1]
- local train2=advtrains.trains[self.train_id_2]
- if not train1 or not train2 then
- atprint("Couple: trains missing, destroying")
- self.object:remove()
- return
- end
-
- --shh, silence here, this is an on-step callback!
- if not advtrains.train_ensure_init(self.train_id_1, train1) then
- --atwarn("Train",self.train_id_1,"is not initialized! Operation aborted!")
- return
- end
- if not advtrains.train_ensure_init(self.train_id_2, train2) then
- --atwarn("Train",self.train_id_2,"is not initialized! Operation aborted!")
- return
- end
-
- if train1.velocity>0 or train2.velocity>0 then
- if not self.position_set then --ensures that train stands a single time before check fires. Using flag below
- return
- end
- atprint("Couple: train is moving, destroying")
- self.object:remove()
- return
+ if not self.train_id_1 or not self.train_id_2 then
+ --atdebug("Couple Removing ids missing")
+ self.object:remove()
+ return
+ end
+ local train1=advtrains.trains[self.train_id_1]
+ local train2=advtrains.trains[self.train_id_2]
+ if not train1 or not train2 then
+ --atdebug("Couple Removing trains missing")
+ self.object:remove()
+ return
+ end
+
+ if self.position_set and train1.velocity>0 or train2.velocity>0 then
+ --atdebug("Couple: train is moving, destroying")
+ self.object:remove()
+ return
+ end
+
+ if not self.position_set then
+ local tp1
+ if self.t1_is_front then
+ tp1=advtrains.path_get_interpolated(train1, train1.index)
+ else
+ tp1=advtrains.path_get_interpolated(train1, train1.end_index)
end
-
- if not self.position_set then
- local tp1
- if self.t1_is_front then
- tp1=advtrains.path_get_interpolated(train1, train1.index)
- else
- tp1=advtrains.path_get_interpolated(train1, train1.end_index)
- end
- local tp2
- if self.t2_is_front then
- tp2=advtrains.path_get_interpolated(train2, train2.index)
- else
- tp2=advtrains.path_get_interpolated(train2, train2.end_index)
- end
- local pos_median=advtrains.pos_median(tp1, tp2)
- if not vector.equals(pos_median, self.object:getpos()) then
- self.object:set_pos(pos_median)
- end
- self.position_set=true
+ local tp2
+ if self.t2_is_front then
+ tp2=advtrains.path_get_interpolated(train2, train2.index)
+ else
+ tp2=advtrains.path_get_interpolated(train2, train2.end_index)
end
- advtrains.atprint_context_tid=nil
- end,
-})
-minetest.register_entity("advtrains:lockmarker", {
- visual="sprite",
- textures = {"advtrains_cpl_lock.png"},
- collisionbox = {-0.3,-0.3,-0.3, 0.3,0.3,0.3},
- visual_size = {x=0.7, y=0.7},
- initial_sprite_basepos = {x=0, y=0},
-
- is_lockmarker=true,
- static_save = false,
- on_activate=function(self, staticdata)
- if staticdata=="COUPLE" then
- --couple entities have no right to exist further...
- atprint("Couple loaded from staticdata, destroying")
- self.object:remove()
- return
+ local pos_median=advtrains.pos_median(tp1, tp2)
+ if not vector.equals(pos_median, self.object:getpos()) then
+ self.object:set_pos(pos_median)
end
- self.object:set_armor_groups({immmortal=1})
- self.life=5
- end,
- get_staticdata=function(self) return "COUPLE" end,
- on_step=function(self, dtime)
- self.life=(self.life or 5)-dtime
- if self.life<0 then
- self.object:remove()
+ self.position_set=true
end
end,
-})
+})
diff --git a/advtrains/doc/advtrains_speed_lessp.3advtrains.md b/advtrains/doc/advtrains_speed_lessp.3advtrains.md
new file mode 100644
index 0000000..663aa42
--- /dev/null
+++ b/advtrains/doc/advtrains_speed_lessp.3advtrains.md
@@ -0,0 +1,15 @@
+% advtrains_speed_lessp(3advtrains) | Advtrains Developer's Manual
+
+# NAME
+`advtrains.speed.lessp`, `advtrains.speed.greaterp`, `advtrains.speed.not_lessp`, `advtrains.speed_not_greaterp`, `advtrains.speed.equalp`, `advtrains.speed.not_equalp`, `advtrains.speed.max`, `advtrains.speed.min` - speed restriction comparison functions
+
+# SYNOPSIS
+Each function takes two arguments and returns a boolean or (for `advtrains.speed.max` and `advtrains.speed.min`) a valid speed limit
+
+# DESCRIPTION
+
+The functions above correspond to the arithmetic `<`, `>`, `>=`, `<=`, `==`, `~=` operators and the `math.max` and `math.min` functions, respectively. The constants `nil` and `false` are treated as -1.
+
+# NOTES
+
+These functions are trivial to implement and the implementation can be easily embedded into existing code. They are simply provided for convenience.
diff --git a/advtrains/doc/advtrains_speed_set_restriction.3advtrains.md b/advtrains/doc/advtrains_speed_set_restriction.3advtrains.md
new file mode 100644
index 0000000..b3183c6
--- /dev/null
+++ b/advtrains/doc/advtrains_speed_set_restriction.3advtrains.md
@@ -0,0 +1,18 @@
+% advtrains_speed_set_restriction(3advtrains) | Advtrains Developer's Manual
+
+# NAME
+`advtrains.speed.set_restriction`, `advtrains.speed.merge_aspect` - modify speed restriction
+
+# SYNOPSIS
+* `advtrains.speed.set_restriction(train, rtype, rval)`
+* `advtrains.speed.merge_aspect(train, asp)`
+
+# DESCRIPTION
+
+The `advtrains.speed.set_restriction` function sets the speed restriction of type `rtype` of `train` to `rval` and updates the speed restriction value to the strictest speed restriction in the table, or `nil` if all speed restrictions are `nil` or `-1`. If the speed restriction table does not exist, it is created with the `"main"` speed restriction being the speed restriction value of `train`.
+
+The `advtrains.speed.merge_aspect` function merges the main aspect of `asp` into the speed restriction table with the same procedure described above. If the signal aspect table does not provide the type of speed restriction, the restriction type `"main"` is assumed.
+
+# SIDE EFFECTS
+
+Both functions modify `train.speed_restriction` and `train.speed_restrictions_t`.
diff --git a/advtrains/doc/signal_aspect.7advtrains.md b/advtrains/doc/signal_aspect.7advtrains.md
new file mode 100644
index 0000000..827760d
--- /dev/null
+++ b/advtrains/doc/signal_aspect.7advtrains.md
@@ -0,0 +1,24 @@
+% signal_aspect(7advtrains) | Advtrains Developer's Manual
+
+# DESCRIPTION
+
+The signal aspect table used by advtrains has the following fields:
+
+* `main`: The main speed restriction
+* `dst`: The `main` aspect of the distant signal (not implemented)
+* `type`: The type of speed restriction given by the signal
+* `shunt`: Whether shunting is allowed
+* `proceed_as_main`: Whether to proceed without shunting
+
+The `main` and `dst` fields may contain the following values:
+* `-1`: No speed restriction
+* `nil`: No information is available
+
+The `type` field can be any valid table index, but it should usually be one of the following values:
+* "main": The main signal aspect used before the introduction of speed restriction types. This is the default value if the `type` field is absent.
+* "line": The speed limit for the physical line.
+* "temp": The speed limit that is temporarily introduced.
+
+# NOTES
+
+A signal with the `main` aspect of zero should not provide distant signal aspect.
diff --git a/advtrains/formspec.lua b/advtrains/formspec.lua
new file mode 100644
index 0000000..8894354
--- /dev/null
+++ b/advtrains/formspec.lua
@@ -0,0 +1,111 @@
+local sformat = string.format
+local fsescape = minetest.formspec_escape
+
+local function make_list(entries)
+ local t = {}
+ for k, v in ipairs(entries) do
+ t[k] = fsescape(v)
+ end
+ return table.concat(t, ",")
+end
+
+local function S_wrapper(f, i0)
+ return function(...)
+ local args = {...}
+ args[i0] = attrans(unpack(args,i0))
+ return f(unpack(args,1,i0))
+ end
+end
+
+local function f_button(x, y, w, id, text)
+ return sformat("button[%f,%f;%f,0.75;%s;%s]", x, y, w, id, text)
+end
+
+local function f_checkbox(x, y, name, selected, label)
+ return sformat("checkbox[%f,%f;%s;%s;%s]", x, y+0.25, name, label, selected and "true" or "false")
+end
+
+local function f_button_exit(x, y, w, id, text)
+ return sformat("button_exit[%f,%f;%f,0.75;%s;%s]", x, y, w, id, text)
+end
+
+local function f_dropdown(x, y, w, id, entries, sel, indexed)
+ return sformat("dropdown[%f,%f;%f,0.75;%s;%s;%d%s]",
+ x, y, w, id, make_list(entries),
+ sel or 1,
+ indexed and ";true" or "")
+end
+
+local function f_image_button(x, y, w, h, texture, id, label, noclip, drawborder, pressed)
+ local st = {string.format("%f,%f;%f,%f;%s;%s;%s", x, y, w, h, fsescape(texture), fsescape(id), fsescape(label))}
+ if pressed then
+ st[#st+1] = tostring(noclip or false)
+ st[#st+1] = tostring(drawborder or false)
+ st[#st+1] = fsescape(pressed)
+ end
+ return sformat("image_button[%s]", table.concat(st, ";"))
+end
+
+local function f_image_button_exit(x, y, w, h, texture, id, label)
+ local st = {string.format("%f,%f;%f,%f;%s;%s;%s", x, y, w, h, fsescape(texture), fsescape(id), fsescape(label))}
+ return sformat("image_button_exit[%s]", table.concat(st, ";"))
+end
+
+local function f_label(x, y, text)
+ return sformat("label[%f,%f;%s]", x, y+0.25, fsescape(text))
+end
+
+local function f_field_aux(x, y, w, id, default)
+ return sformat("field[%f,%f;%f,0.75;%s;;%s]", x, y, w, id, default)
+end
+
+local function f_field(x, y, w, id, label, default)
+ return f_label(x, y-0.5, label) .. f_field_aux(x, y, w, id, default)
+end
+
+local function f_tabheader(x, y, w, h, id, entries, sel, transparent, border)
+ local st = {string.format("%f,%f",x, y)}
+ if h then
+ if w then
+ st[#st+1] = string.format("%f,%f", w, h)
+ else
+ st[#st+1] = tostring(h)
+ end
+ end
+ st[#st+1] = tostring(id)
+ st[#st+1] = make_list(entries)
+ st[#st+1] = tostring(sel)
+ if transparent ~= nil then
+ st[#st+1] = tostring(transparent)
+ if border ~= nil then
+ st[#st+1] = tostring(border)
+ end
+ end
+ return string.format("tabheader[%s]", table.concat(st, ";"))
+end
+
+local function f_textlist(x, y, w, h, id, entries, sel, transparent)
+ local st = {string.format("%f,%f;%f,%f;%s;%s", x, y, w, h, id, make_list(entries))}
+ if sel then
+ st[#st+1] = tostring(sel)
+ st[#st+1] = tostring(transparent or false)
+ end
+ return string.format("textlist[%s]", table.concat(st, ";"))
+end
+
+return {
+ button = f_button,
+ S_button = S_wrapper(f_button, 5),
+ checkbox = f_checkbox,
+ S_checkbox = S_wrapper(f_checkbox, 5),
+ button_exit = f_button_exit,
+ S_button_exit = S_wrapper(f_button_exit, 5),
+ dropdown = f_dropdown,
+ field = f_field,
+ image_button = f_image_button,
+ image_button_exit = f_image_button_exit,
+ label = f_label,
+ S_label = S_wrapper(f_label, 3),
+ tabheader = f_tabheader,
+ textlist = f_textlist,
+}
diff --git a/advtrains/init.lua b/advtrains/init.lua
index 96352df..1cba255 100644
--- a/advtrains/init.lua
+++ b/advtrains/init.lua
@@ -24,6 +24,9 @@ minetest.log("action", "[advtrains] Loading...")
-- There is no need to support 0.4.x anymore given that the compatitability with it is already broken by 1bb1d825f46af3562554c12fba35a31b9f7973ff
attrans = minetest.get_translator ("advtrains")
+function attrans_formspec(...)
+ return minetest.formspec_escape(attrans(...))
+end
--advtrains
advtrains = {trains={}, player_to_train_mapping={}}
@@ -198,6 +201,9 @@ advtrains.meseconrules =
advtrains.fpath=minetest.get_worldpath().."/advtrains"
+advtrains.speed = dofile(advtrains.modpath.."/speed.lua")
+advtrains.formspec = dofile(advtrains.modpath.."/formspec.lua")
+
dofile(advtrains.modpath.."/path.lua")
dofile(advtrains.modpath.."/trainlogic.lua")
dofile(advtrains.modpath.."/trainhud.lua")
@@ -467,8 +473,8 @@ advtrains.avt_save = function(remove_players_from_wagons)
"trainparts", "recently_collided_with_env",
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
"text_outside", "text_inside", "line", "routingcode",
- "il_sections", "speed_restriction", "is_shunt",
- "points_split", "autocouple", "ars_disable",
+ "il_sections", "speed_restriction", "speed_restrictions_t", "is_shunt",
+ "points_split", "autocouple", "atc_wait_autocouple", "ars_disable",
})
--then save it
tmp_trains[id]=v
@@ -569,11 +575,13 @@ advtrains.mainloop_runcnt=0
advtrains.global_slowdown = 1
local t = 0
+local within_mainstep = false
minetest.register_globalstep(function(dtime_mt)
if no_action then
-- the advtrains globalstep is skipped by command. Return immediately
return
end
+ within_mainstep = true
advtrains.mainloop_runcnt=advtrains.mainloop_runcnt+1
--atprint("Running the main loop, runcnt",advtrains.mainloop_runcnt)
@@ -586,6 +594,7 @@ minetest.register_globalstep(function(dtime_mt)
if GENERATE_ATRICIFIAL_LAG then
dtime = HOW_MANY_LAG
if os.clock()<t then
+ within_mainstep = false
return
end
@@ -616,7 +625,7 @@ minetest.register_globalstep(function(dtime_mt)
if advtrains.lines then
advtrains.lines.step(dtime)
end
-
+
--trigger a save when necessary
save_timer=save_timer-dtime
if save_timer<=0 then
@@ -626,6 +635,9 @@ minetest.register_globalstep(function(dtime_mt)
save_timer = advtrains.SAVE_INTERVAL
atprintbm("saving", t)
end
+
+ within_mainstep = false
+
end)
--if something goes wrong in these functions, there is no help. no pcall here.
@@ -678,7 +690,13 @@ function advtrains.save(remove_players_from_wagons)
--TODO very simple yet hacky workaround for the "green signals" bug
advtrains.invalidate_all_paths()
end
-minetest.register_on_shutdown(advtrains.save)
+minetest.register_on_shutdown(function()
+ if within_mainstep then
+ atwarn("Crash during advtrains main step - skipping the shutdown save operation to not save inconsistent data!")
+ else
+ advtrains.save()
+ end
+end)
-- This chat command provides a solution to the problem known on the LinuxWorks server
-- There are many players that joined a single time, got on a train and then left forever
diff --git a/advtrains/locale/advtrains.de.tr b/advtrains/locale/advtrains.de.tr
index cd43eed..6abbc12 100644
--- a/advtrains/locale/advtrains.de.tr
+++ b/advtrains/locale/advtrains.de.tr
@@ -70,3 +70,8 @@ This track can not be removed!=Diese Schiene kann nicht entfernt werden!
Position is occupied by a train.=Ein Zug steht an dieser Position.
There's a Track Circuit Break here.=Hier ist eine Gleisabschnittsgrenze (TCB).
There's a Signal Influence Point here.=Hier ist ein Signal-Beeinflussungspunkt.
+Buffer and Chain Coupler=Schraubenkupplung
+Scharfenberg Coupler=Scharfenbergkupplung
+Japanese Train Inter-Wagon Connection=Waggonzwischenverbindung Japanischer Personenzug
+Can not couple: The couplers of the trains do not match (@1 and @2).=Kann nicht ankuppeln: Die Kupplungen der Züge passen nicht zueinander (@1 und @2)
+<none>=<keine>
diff --git a/advtrains/lzb.lua b/advtrains/lzb.lua
index cbdc422..64e4553 100644
--- a/advtrains/lzb.lua
+++ b/advtrains/lzb.lua
@@ -90,7 +90,7 @@ local function look_ahead(id, train)
--local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + params.BRAKE_SPACE)
-- worst case (don't use index_by_offset)
local brake_i = atfloor(train.index + brakedst + params.BRAKE_SPACE)
- atprint("LZB: looking ahead up to ", brake_i)
+ --atprint("LZB: looking ahead up to ", brake_i)
--local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE)
@@ -134,7 +134,7 @@ local function call_runover_callbacks(id, train)
local ckp = train.lzb.checkpoints
while ckp[i] do
if ckp[i].index <= idx then
- atprint("LZB: checkpoint run over: i=",ckp[i].index,"s=",ckp[i].speed)
+ --atprint("LZB: checkpoint run over: i=",ckp[i].index,"s=",ckp[i].speed,"p=",ckp[i].pos)
-- call callback
local it = ckp[i]
if it.callback then
@@ -153,7 +153,7 @@ local function apply_checkpoint_to_path(train, checkpoint)
if not checkpoint.speed then
return
end
- atprint("LZB: applying checkpoint: i=",checkpoint.index,"s=",checkpoint.speed)
+ --atprint("LZB: applying checkpoint: i=",checkpoint.index,"s=",checkpoint.speed,"p=",checkpoint.pos)
if checkpoint.speed == 0 then
train.lzb.zero_checkpoint = true
@@ -196,6 +196,9 @@ s = v0 * ------- + - * | ------- | = -----------
-- Removes all LZB checkpoints and restarts the traverser at the current train index
function advtrains.lzb_invalidate(train)
+ --advtrains.atprint_context_tid = train.id
+ --atprint("LZB: invalidate")
+ --advtrains.atprint_context_tid = nil
train.lzb = {
trav_index = atfloor(train.index) + 1,
checkpoints = {},
@@ -205,8 +208,11 @@ end
-- LZB part of path_invalidate_ahead. Clears all checkpoints that are ahead of start_idx
-- in contrast to path_inv_ahead, doesn't complain if start_idx is behind train.index, clears everything then
function advtrains.lzb_invalidate_ahead(train, start_idx)
+ --advtrains.atprint_context_tid = train.id
+ --atprint("LZB: invalidate ahead i=",start_idx)
if train.lzb then
local idx = atfloor(start_idx)
+ --atprint("LZB: invalidate ahead p=",train.path[start_idx])
local i = 1
while train.lzb.checkpoints[i] do
if train.lzb.checkpoints[i].index >= idx then
@@ -225,6 +231,7 @@ function advtrains.lzb_invalidate_ahead(train, start_idx)
apply_checkpoint_to_path(train, ckp)
end
end
+ --advtrains.atprint_context_tid = nil
end
-- Add LZB control point
diff --git a/advtrains/nodedb.lua b/advtrains/nodedb.lua
index 36b5dea..41ac089 100644
--- a/advtrains/nodedb.lua
+++ b/advtrains/nodedb.lua
@@ -302,7 +302,7 @@ ndb.run_lbm = function(pos, node)
minetest.swap_node(pos, newnode)
local ndef=minetest.registered_nodes[nodeid]
if ndef and ndef.advtrains and ndef.advtrains.on_updated_from_nodedb then
- ndef.advtrains.on_updated_from_nodedb(pos, newnode)
+ ndef.advtrains.on_updated_from_nodedb(pos, newnode, node)
end
return true
end
diff --git a/advtrains/path.lua b/advtrains/path.lua
index 714781a..f2b8a13 100644
--- a/advtrains/path.lua
+++ b/advtrains/path.lua
@@ -417,3 +417,42 @@ function advtrains.path_lookup(train, pos)
end
return nil
end
+
+-- Projects the path of "train" onto the path of "onto_train_id", and returns the index on onto_train's path
+-- that corresponds to "index" on "train"'s path, as well as whether both trains face each other
+-- index may be fractional
+-- returns: res_index, trains_facing
+-- returns nil when path can not be projected, either because trains are on different tracks or
+-- node at "index" happens to be on a turnout and it's the wrong direction
+-- Note - duplicate with similar functionality is in train_step_b() - that code combines train detection with projecting
+function advtrains.path_project(train, index, onto_train_id)
+ local base_idx = atfloor(index)
+ local frac_part = index - base_idx
+ local base_pos = advtrains.path_get(train, base_idx)
+ local base_cn = train.path_cn[base_idx]
+ local otrn = advtrains.trains[onto_train_id]
+ -- query occupation
+ local occ = advtrains.occ.get_trains_over(base_pos)
+ -- is wanted train id contained?
+ local ob_idx = occ[onto_train_id]
+ if not ob_idx then
+ return nil
+ end
+
+ -- retrieve other train's cn and cp
+ local ocn = otrn.path_cn[ob_idx]
+ local ocp = otrn.path_cp[ob_idx]
+
+ if base_cn == ocn then
+ -- same direction
+ return ob_idx + frac_part, false
+ elseif base_cn == ocp then
+ -- facing trains - subtract index frac
+ return ob_idx - frac_part, true
+ else
+ -- same path item but no common connections - deny
+ return nil
+ end
+end
+
+
diff --git a/advtrains/settingtypes.txt b/advtrains/settingtypes.txt
index 6acff80..2b627cb 100644
--- a/advtrains/settingtypes.txt
+++ b/advtrains/settingtypes.txt
@@ -56,3 +56,8 @@ advtrains_dtime_limit (DTime Limit for slow-down) float 0.2 0 5
# Time interval in seconds in which advtrains stores its save data to disk
# Nevertheless, advtrains saves all data when shutting down the server.
advtrains_save_interval (Save Interval) int 60 20 3600
+
+# Enable forgiving collision mode
+# If enabled, trains only collide with nodes with "normal" drawtype.
+advtrains_forgiving_collision (Forgiving Collision mode) bool false
+
diff --git a/advtrains/signals.lua b/advtrains/signals.lua
index 5fb1d1b..b26c950 100644
--- a/advtrains/signals.lua
+++ b/advtrains/signals.lua
@@ -18,7 +18,7 @@ end
local function aspect(b)
return {
- main = (not b) and 0, -- b ? false : 0
+ main = b and -1 or 0,
shunt = false,
proceed_as_main = true,
dst = false,
@@ -27,7 +27,7 @@ return {
end
local suppasp = {
- main = {0, false},
+ main = {0, -1},
dst = {false},
shunt = nil,
proceed_as_main = true,
diff --git a/advtrains/spec/speed_spec.lua b/advtrains/spec/speed_spec.lua
new file mode 100644
index 0000000..97f8ffa
--- /dev/null
+++ b/advtrains/spec/speed_spec.lua
@@ -0,0 +1,70 @@
+package.path = "../?.lua;" .. package.path
+advtrains = {}
+_G.advtrains = advtrains
+local speed = require("speed")
+
+describe("Arithmetic functions on speed restrictions", function()
+ it("should work", function()
+ local a = math.random()
+ local b = math.random(20)
+ -- This test is basically a "typo check"
+ assert.is_true (speed.lessp(a, b))
+ assert.is_false(speed.greaterp(a, b))
+ assert.is_false(speed.not_lessp(a, b))
+ assert.is_true (speed.not_greaterp(a, b))
+ assert.is_false(speed.lessp(a, a))
+ assert.is_false(speed.greaterp(a, a))
+ assert.is_true (speed.equalp(a, a))
+ assert.is_false(speed.not_equalp(a, a))
+ assert.equal(b, speed.max(a, b))
+ assert.equal(a, speed.min(a, b))
+ end)
+ it("should handle -1", function()
+ assert.is_false(speed.lessp(-1, math.random()))
+ end)
+ it("should handle nil", function()
+ assert.is_true(speed.greaterp(nil, math.random()))
+ end)
+ it("should handle mixed nil and -1", function()
+ assert.is_true(speed.equalp(nil, -1))
+ end)
+end)
+
+describe("The speed restriction setter", function()
+ it("should set the signal aspect", function()
+ local t = {speed_restrictions_t = {x = 5, y = 9}}
+ local u = {speed_restrictions_t = {x = 7, y = 9}, speed_restriction = 7}
+ speed.merge_aspect(t, {main = 7, type = "x"})
+ assert.same(u, t)
+ end)
+ it("should work with existing signal aspect tables", function()
+ local t = {speed_restrictions_t = {main = 5, foo = 3}}
+ local u = {speed_restrictions_t = {main = 7, foo = 3}, speed_restriction = 3}
+ speed.merge_aspect(t, {main = 7})
+ assert.same(u, t)
+ end)
+ it("should work with distant signals", function()
+ local t = {speed_restrictions_t = {main = 5}}
+ local u = {speed_restrictions_t = {main = 5}, speed_restriction = 5}
+ speed.merge_aspect(t, {})
+ assert.same(u, t)
+ end)
+ it("should create the restriction table if necessary", function()
+ local t = {speed_restriction = 5}
+ local u = {speed_restriction = 3, speed_restrictions_t = {main = 5, foo = 3}}
+ speed.merge_aspect(t, {main = 3, type = "foo"})
+ assert.same(u, t)
+ end)
+ it("should also create the restriction table for trains without any speed limit", function()
+ local t = {}
+ local u = {speed_restrictions_t = {}}
+ speed.merge_aspect(t, {})
+ assert.same(u, t)
+ end)
+ it("should set the speed restriction to nil if that is the case", function()
+ local t = {speed_restriction = math.random(20)}
+ local u = {speed_restrictions_t = {main = -1}}
+ speed.merge_aspect(t, {main = -1})
+ assert.same(u, t)
+ end)
+end)
diff --git a/advtrains/speed.lua b/advtrains/speed.lua
new file mode 100644
index 0000000..ec4f928
--- /dev/null
+++ b/advtrains/speed.lua
@@ -0,0 +1,88 @@
+-- auxiliary functions for the reworked speed restriction system
+
+local function s_lessp(a, b)
+ if not a or a == -1 then
+ return false
+ elseif not b or b == -1 then
+ return true
+ else
+ return a < b
+ end
+end
+
+local function s_greaterp(a, b)
+ return s_lessp(b, a)
+end
+
+local function s_not_lessp(a, b)
+ return not s_lessp(a, b)
+end
+
+local function s_not_greaterp(a, b)
+ return not s_greaterp(a, b)
+end
+
+local function s_equalp(a, b)
+ return (a or -1) == (b or -1)
+end
+
+local function s_not_equalp(a, b)
+ return (a or -1) ~= (b or -1)
+end
+
+local function s_max(a, b)
+ if s_lessp(a, b) then
+ return b
+ else
+ return a
+ end
+end
+
+local function s_min(a, b)
+ if s_lessp(a, b) then
+ return a
+ else
+ return b
+ end
+end
+
+local function get_speed_restriction_from_table (tbl)
+ local strictest = -1
+ for _, v in pairs(tbl) do
+ strictest = s_min(strictest, v)
+ end
+ if strictest == -1 then
+ return nil
+ end
+ return strictest
+end
+
+local function set_speed_restriction (tbl, rtype, rval)
+ if rval then
+ tbl[rtype or "main"] = rval
+ end
+ return tbl
+end
+
+local function set_speed_restriction_for_train (train, rtype, rval)
+ local t = train.speed_restrictions_t or {main = train.speed_restriction}
+ train.speed_restrictions_t = set_speed_restriction(t, rtype, rval)
+ train.speed_restriction = get_speed_restriction_from_table(t)
+end
+
+local function merge_speed_restriction_from_aspect_to_train (train, asp)
+ return set_speed_restriction_for_train(train, asp.type, asp.main)
+end
+
+return {
+ lessp = s_lessp,
+ greaterp = s_greaterp,
+ not_lessp = s_not_lessp,
+ not_greaterp = s_not_greaterp,
+ equalp = s_equalp,
+ not_equalp = s_not_equalp,
+ max = s_max,
+ min = s_min,
+ set_restriction = set_speed_restriction_for_train,
+ merge_aspect = merge_speed_restriction_from_aspect_to_train,
+}
diff --git a/advtrains/trainhud.lua b/advtrains/trainhud.lua
index 6e69455..22aa6cf 100644
--- a/advtrains/trainhud.lua
+++ b/advtrains/trainhud.lua
@@ -281,6 +281,8 @@ function advtrains.hud_train_format(train, flip)
local oc = lzb.checkpoints
for i = 1, #oc do
local spd = oc[i].speed
+ spd = advtrains.speed.min(spd, train.speed_restriction)
+ if spd == -1 then spd = nil end
local c = not spd and "lime" or (type(spd) == "number" and (spd == 0) and "red" or "orange") or nil
if c then
ht[#ht+1] = sformat("130,10=(advtrains_hud_bg.png^[resize\\:30x5^[colorize\\:%s)",c)
diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua
index 187e5ba..a0fdaa1 100644
--- a/advtrains/trainlogic.lua
+++ b/advtrains/trainlogic.lua
@@ -139,11 +139,15 @@ minetest.register_on_joinplayer(function(player)
advtrains.hhud[player:get_player_name()] = nil
--independent of this, cause all wagons of the train which are loaded to reattach their players
--needed because already loaded wagons won't call reattach_all()
+ local pname = player:get_player_name()
local id=advtrains.player_to_train_mapping[pname]
if id then
for _,wagon in pairs(minetest.luaentities) do
- if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
- wagon:reattach_all()
+ if wagon.is_wagon and wagon.initialized and wagon.id then
+ local wdata = advtrains.wagons[wagon.id]
+ if wdata and wdata.train_id == id then
+ wagon:reattach_all()
+ end
end
end
end
@@ -250,6 +254,11 @@ local callbacks_update, run_callbacks_update = mkcallback("update")
local callbacks_create, run_callbacks_create = mkcallback("create")
local callbacks_remove, run_callbacks_remove = mkcallback("remove")
+-- required to call from couple.lua
+function advtrains.update_train_start_and_end(train)
+ recalc_end_index(train)
+ run_callbacks_update(train.id, train)
+end
-- train_ensure_init: responsible for creating a state that we can work on, after one of the following events has happened:
-- - the train's path got cleared
@@ -386,7 +395,7 @@ function advtrains.train_step_b(id, train, dtime)
-- interlocking speed restriction
elseif train.speed_restriction then
--atprint("in train_step_b: applying interlocking speed restriction",train.speed_restriction)
- sit_v_cap = train.speed_restriction
+ sit_v_cap = math.min(sit_v_cap or math.huge, train.speed_restriction)
end
--apply off-track handling:
@@ -394,7 +403,7 @@ function advtrains.train_step_b(id, train, dtime)
local back_off_track=train.end_index<train.path_trk_b
train.off_track = front_off_track or back_off_track
- if back_off_track and (not v_cap or v_cap > 1) then
+ if back_off_track and (not sit_v_cap or sit_v_cap > 1) then
--atprint("in train_step_b: applying back_off_track")
sit_v_cap = 1
elseif front_off_track then
@@ -417,9 +426,11 @@ function advtrains.train_step_b(id, train, dtime)
ctrl_lever = userc
else
if train.atc_command then
- if (not train.atc_delay or train.atc_delay<=0) and not train.atc_wait_finish then
+ if (not train.atc_delay or train.atc_delay<=0)
+ and not train.atc_wait_finish
+ and not train.atc_wait_autocouple then
advtrains.atc.execute_atc_command(id, train)
- else
+ elseif train.atc_delay and train.atc_delay > 0 then
train.atc_delay=train.atc_delay-dtime
end
elseif train.atc_delay then
@@ -587,12 +598,77 @@ function advtrains.train_step_b(id, train, dtime)
else
--atprint("in train_step_b: movement calculation reusing from LZB newindex=",new_index_curr_tv)
end
-
+
-- if the zeroappr mechanism has hit, go no further than zeroappr index
if lzb_next_zero_barrier and new_index_curr_tv > lzb_next_zero_barrier then
--atprint("in train_step_b: Zero barrier hit, clipping to newidx_tv=",new_index_curr_tv, "zb_idx=",lzb_next_zero_barrier)
new_index_curr_tv = lzb_next_zero_barrier
end
+
+ -- New same-track collision system - check for any other trains within the range we're going to move
+ -- do the checks if we either are moving or about to start moving
+ if new_index_curr_tv > train.index or accelerating then -- only if train is actually advancing
+ -- Note: duplicate code from path_project() because of subtle differences: no frac processing and scanning all occupations
+ --[[train.debug = ""
+ local atdebug = function(t, ...)
+ local text=advtrains.print_concat_table({t, ...})
+ train.debug = train.debug..text.."\n"
+ end]]
+ local base_idx = atfloor(new_index_curr_tv + 1)
+ local base_pos = advtrains.path_get(train, base_idx)
+ local base_cn = train.path_cn[base_idx]
+ --atdebug(id,"Begin Checking for on-track collisions new_idx=",new_index_curr_tv,"base_idx=",base_idx,"base_pos=",base_pos,"base_cn=",base_cn)
+ -- query occupation
+ local occ = advtrains.occ.get_trains_over(base_pos)
+ -- iterate other trains
+ for otid, ob_idx in pairs(occ) do
+ if otid ~= id then
+ --atdebug(id,"Found other train",otid," with matching index ",ob_idx)
+ -- Phase 1 - determine if trains are facing and which is the relefant stpo index
+ local otrn = advtrains.trains[otid]
+
+ -- retrieve other train's cn and cp
+ local ocn = otrn.path_cn[ob_idx]
+ local ocp = otrn.path_cp[ob_idx]
+
+ local target_is_inside, ref_index, facing
+
+ if base_cn == ocn then
+ -- same direction
+ ref_index = otrn.end_index
+ same_dir = true
+ target_is_inside = (ob_idx >= ref_index)
+ --atdebug("Same direction: ref_index",ref_index,"inside=",target_is_inside)
+ elseif base_cn == ocp then
+ -- facing trains - subtract index frac
+ ref_index = otrn.index
+ same_dir = false
+ target_is_inside = (ob_idx <= ref_index)
+ --atdebug("Facing direction: ref_index",ref_index,"inside=",target_is_inside)
+ end
+
+ -- Phase 2 - project ref_index back onto our path and check again (necessary because there might be a turnout on the way and we are driving into the flank
+ if target_is_inside then
+ local our_index = advtrains.path_project(otrn, ref_index, id)
+ --atdebug("Backprojected our_index",our_index)
+ if our_index and our_index <= new_index_curr_tv
+ and our_index >= train.index then --FIX: If train was already past the collision point in the previous step, there is no collision! Fixes bug with split_at_index
+ -- ON_TRACK COLLISION IS HAPPENING
+ -- the actual collision is handled in train_step_c, so set appropriate signal variables
+ train.ontrack_collision_info = {
+ otid = otid,
+ same_dir = same_dir,
+ }
+ -- clip newindex
+ --atdebug("-- Collision detected!")
+ new_index_curr_tv = our_index
+ end
+ end
+ end
+ end
+ end
+
+ -- ## Movement happens here ##
train.index = new_index_curr_tv
recalc_end_index(train)
@@ -638,21 +714,45 @@ function advtrains.train_step_c(id, train, dtime)
advtrains.spawn_wagons(id)
train.check_trainpartload=2
end
-
- --- 8. check for collisions with other trains and damage players ---
-
+
local train_moves=(train.velocity~=0)
-
- --- Check whether this train can be coupled to another, and set couple entities accordingly
- if not train.was_standing and not train_moves then
- advtrains.train_check_couples(train)
+ local very_short_train = train.trainlen < 3
+
+ --- On-track collision handling - detected in train_step_b, but handled here so all other train movements have already happened.
+ if train.ontrack_collision_info then
+ train.velocity = 0
+ train.acceleration = 0
+ --advtrains.atc.train_reset_command(train) will occur in couple_initiate_with if required
+
+ local otrn = advtrains.trains[train.ontrack_collision_info.otid]
+
+ if otrn.velocity == 0 then -- other train must be standing, else don't initiate coupling
+ advtrains.couple_initiate_with(train, otrn, not train.ontrack_collision_info.same_dir)
+ else
+ -- other collision - stop any ATC control
+ advtrains.atc.train_reset_command(train)
+ end
+
+ train.ontrack_collision_info = nil
+ train.couples_up_to_date = true
end
- train.was_standing = not train_moves
-
+
+ -- handle couples if on_track collision handling did not fire
if train_moves then
-
+ train.couples_up_to_date = nil
+ elseif not train.couples_up_to_date then
+ if not very_short_train then -- old coupling system is buggy for short trains
+ advtrains.train_check_couples(train) -- no guarantee for train order here
+ end
+ train.couples_up_to_date = true
+ end
+
+ --- 8. check for collisions with other trains and damage players ---
+ if train_moves then
+ -- Note: this code handles collisions with trains that are not on the same path as the current train
+ -- The same-track collisions and coupling handling is found in couple.lua and handled from train_step_b() and code 2 blocks above.
local collided = false
- local coll_grace=1
+ local coll_grace=2
local collindex = advtrains.path_get_index_by_offset(train, train.index, -coll_grace)
local collpos = advtrains.path_get(train, atround(collindex))
if collpos then
@@ -663,13 +763,14 @@ function advtrains.train_step_c(id, train, dtime)
local testpos=vector.add(rcollpos, {x=x, y=0, z=z})
--- 8a Check collision ---
if not collided then
-
- local col_tr = advtrains.occ.check_collision(testpos, id)
- if col_tr then
- advtrains.train_check_couples(train)
- train.velocity = 0
- advtrains.atc.train_reset_command(train)
- collided = true
+ if not very_short_train then -- position collision system is buggy for short trains
+ local col_tr = advtrains.occ.check_collision(testpos, id)
+ if col_tr then
+ train.velocity = 0
+ train.acceleration = 0
+ advtrains.atc.train_reset_command(train)
+ collided = true
+ end
end
--- 8b damage players ---
@@ -703,7 +804,7 @@ function advtrains.train_step_c(id, train, dtime)
local objs = minetest.get_objects_inside_radius(rcollpos, 2)
for _,obj in ipairs(objs) do
if not obj:is_player() and obj:get_armor_groups().fleshy and obj:get_armor_groups().fleshy > 0
- and obj:get_luaentity() and obj:get_luaentity().name~="signs:text" then
+ and obj:get_luaentity() and obj:get_luaentity().name~="signs_lib:text" then
obj:punch(obj, 1, { full_punch_interval = 1.0, damage_groups = {fleshy = 1000}, }, nil)
end
end
@@ -899,7 +1000,7 @@ function advtrains.remove_train(id)
run_callbacks_remove(id, train)
- advtrains.path_invalidate(train)
+ advtrains.path_invalidate(train, true)
advtrains.couple_invalidate(train)
local tp = train.trainparts
@@ -1019,55 +1120,9 @@ function advtrains.spawn_wagons(train_id)
end
end
-function advtrains.split_train_at_fc(train, count_empty, length_limit)
- -- splits train at first different current FC by convention,
- -- locomotives have empty FC so are ignored
- -- count_empty is used to split off locomotives
- -- length_limit limits the length of the first train to length_limit wagons
- local train_id = train.id
- local fc = false
- local ind = 0
- for i = 1, #train.trainparts do
- local w_id = train.trainparts[i]
- local data = advtrains.wagons[w_id]
- if length_limit and i > length_limit then
- ind = i
- break
- end
- if data then
- local wfc = advtrains.get_cur_fc(data)
- if wfc ~= "" or count_empty then
- if fc then
- if fc ~= wfc then
- ind = i
- break
- end
- else
- fc = wfc
- end
- end
- end
- end
- if ind > 0 then
- return advtrains.split_train_at_index(train, ind), fc
- end
- if fc then
- return nil, fc
- end
-end
-
-function advtrains.train_step_fc(train)
- for i=1,#train.trainparts do
- local w_id = train.trainparts[i]
- local data = advtrains.wagons[w_id]
- if data then
- advtrains.step_fc(data)
- end
- end
-end
-
function advtrains.split_train_at_index(train, index)
-- this function splits a train at index, creating a new train from the back part of the train.
+ --atdebug("split_train_at_index invoked on",train.id,"index",index)
local train_id=train.id
if index > #train.trainparts then
@@ -1090,6 +1145,7 @@ function advtrains.split_train_at_index(train, index)
local p_index=advtrains.path_get_index_by_offset(train, train.index, - data.pos_in_train + wagon.wagon_span)
local pos, connid, frac = advtrains.path_getrestore(train, p_index)
+ --atdebug("new train position p_index",p_index,"pos",pos,"connid",connid,"frac",frac)
local tp = {}
for k,v in ipairs(train.trainparts) do
if k >= index then
@@ -1099,12 +1155,14 @@ function advtrains.split_train_at_index(train, index)
end
advtrains.update_trainpart_properties(train_id)
recalc_end_index(train)
+ --atdebug("old train index",train.index,"end_index",train.end_index)
run_callbacks_update(train_id, train)
--create subtrain
local newtrain_id=advtrains.create_new_train_at(pos, connid, frac, tp)
local newtrain=advtrains.trains[newtrain_id]
-
+ --atdebug("new train created with ID",newtrain_id,"index",newtrain.index,"end_index",newtrain.end_index)
+
newtrain.velocity=train.velocity
-- copy various properties from the old to the new train
newtrain.door_open = train.door_open
@@ -1113,6 +1171,7 @@ function advtrains.split_train_at_index(train, index)
newtrain.line = train.line
newtrain.routingcode = train.routingcode
newtrain.speed_restriction = train.speed_restriction
+ newtrain.speed_restrictions_t = table.copy(train.speed_restrictions_t or {main=train.speed_restriction})
newtrain.is_shunt = train.is_shunt
newtrain.points_split = advtrains.merge_tables(train.points_split)
newtrain.autocouple = train.autocouple
@@ -1121,167 +1180,6 @@ function advtrains.split_train_at_index(train, index)
end
-function advtrains.split_train_at_wagon(wagon_id)
- --get train
- local data = advtrains.wagons[wagon_id]
- advtrains.split_train_at_index(advtrains.trains[data.train_id], data.pos_in_trainparts)
-end
-
--- coupling
-local CPL_CHK_DST = -1
-local CPL_ZONE = 2
-
--- train.couple_* contain references to ObjectRefs of couple objects, which contain all relevant information
--- These objectRefs will delete themselves once the couples no longer match
-local function createcouple(pos, train1, t1_is_front, train2, t2_is_front)
- local id1 = train1.id
- local id2 = train2.id
- if train1.autocouple or train2.autocouple then
- -- couple trains
- train1.autocouple = nil
- train2.autocouple = nil
- minetest.after(0, advtrains.safe_couple_trains, id1, id2, t1_is_front, t2_is_front, false, false, train1.velocity, train2.velocity)
- return
- end
-
- local obj=minetest.add_entity(pos, "advtrains:couple")
- if not obj then error("Failed creating couple object!") return end
- local le=obj:get_luaentity()
- le.train_id_1=id1
- le.train_id_2=id2
- le.t1_is_front=t1_is_front
- le.t2_is_front=t2_is_front
- --atdebug("created couple between",train1.id,t1_is_front,train2.id,t2_is_front)
- if t1_is_front then
- train1.cpl_front = obj
- else
- train1.cpl_back = obj
- end
- if t2_is_front then
- train2.cpl_front = obj
- else
- train2.cpl_back = obj
- end
-
-end
-
-function advtrains.train_check_couples(train)
- --atdebug("rechecking couples")
- if train.cpl_front then
- if not train.cpl_front:get_yaw() then
- -- objectref is no longer valid. reset.
- train.cpl_front = nil
- end
- end
- if not train.cpl_front then
- -- recheck front couple
- local front_trains, pos = advtrains.occ.get_occupations(train, atround(train.index) + CPL_CHK_DST)
- if advtrains.is_node_loaded(pos) then -- if the position is loaded...
- for tid, idx in pairs(front_trains) do
- local other_train = advtrains.trains[tid]
- if not advtrains.train_ensure_init(tid, other_train) then
- atwarn("Train",tid,"is not initialized! Couldn't check couples!")
- return
- end
- --atdebug(train.id,"front: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
- if other_train.velocity == 0 then
- if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
- createcouple(pos, train, true, other_train, true)
- break
- end
- if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
- createcouple(pos, train, true, other_train, false)
- break
- end
- end
- end
- end
- end
- if train.cpl_back then
- if not train.cpl_back:get_yaw() then
- -- objectref is no longer valid. reset.
- train.cpl_back = nil
- end
- end
- if not train.cpl_back then
- -- recheck back couple
- local back_trains, pos = advtrains.occ.get_occupations(train, atround(train.end_index) - CPL_CHK_DST)
- if advtrains.is_node_loaded(pos) then -- if the position is loaded...
- for tid, idx in pairs(back_trains) do
- local other_train = advtrains.trains[tid]
- if not advtrains.train_ensure_init(tid, other_train) then
- atwarn("Train",tid,"is not initialized! Couldn't check couples!")
- return
- end
- if other_train.velocity == 0 then
- if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
- createcouple(pos, train, false, other_train, true)
- break
- end
- if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
- createcouple(pos, train, false, other_train, false)
- break
- end
- end
- end
- end
- end
-end
-
-function advtrains.couple_invalidate(train)
- if train.cpl_back then
- train.cpl_back:remove()
- train.cpl_back = nil
- end
- if train.cpl_front then
- train.cpl_front:remove()
- train.cpl_front = nil
- end
- train.was_standing = nil
-end
-
--- relevant code for this comment is in couple.lua
-
---there are 4 cases:
---1/2. F<->R F<->R regular, put second train behind first
---->frontpos of first train will match backpos of second
---3. F<->R R<->F flip one of these trains, take the other as new train
---->backpos's will match
---4. R<->F F<->R flip one of these trains and take it as new parent
---->frontpos's will match
-
-
-function advtrains.do_connect_trains(first_id, second_id, vel)
- local first, second=advtrains.trains[first_id], advtrains.trains[second_id]
-
- if not advtrains.train_ensure_init(first_id, first) then
- atwarn("Train",first_id,"is not initialized! Operation aborted!")
- return
- end
- if not advtrains.train_ensure_init(second_id, second) then
- atwarn("Train",second_id,"is not initialized! Operation aborted!")
- return
- end
-
- local first_wagoncnt=#first.trainparts
- local second_wagoncnt=#second.trainparts
-
- for _,v in ipairs(second.trainparts) do
- table.insert(first.trainparts, v)
- end
-
- advtrains.remove_train(second_id)
- if vel < 0 then
- advtrains.invert_train(first_id)
- vel = -vel
- end
- first.velocity= vel or 0
-
- advtrains.update_trainpart_properties(first_id)
- advtrains.couple_invalidate(first)
- return true
-end
-
function advtrains.invert_train(train_id)
local train=advtrains.trains[train_id]
@@ -1316,10 +1214,10 @@ function advtrains.invert_train(train_id)
-- If interlocking present, check whether this train is in a section and then set as shunt move after reversion
if advtrains.interlocking and train.il_sections and #train.il_sections > 0 then
train.is_shunt = true
- train.speed_restriction = advtrains.SHUNT_SPEED_MAX
+ advtrains.speed.set_restriction(train, "main", advtrains.SHUNT_SPEED_MAX)
else
train.is_shunt = false
- train.speed_restriction = nil
+ advtrains.speed.set_restriction(train, "main", -1)
end
end
@@ -1368,44 +1266,61 @@ function advtrains.invalidate_path(id)
end
--not blocking trains group
-function advtrains.train_collides(node)
- if node and minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].walkable then
+
+if minetest.settings:get_bool("advtrains_forgiving_collision") then
+ function advtrains.train_collides(node)
+ if node and minetest.registered_nodes[node.name] then
+ local ndef = minetest.registered_nodes[node.name]
+ -- if the node is drawtype normal (that is a full cube) then it does collide
+ if ndef.drawtype == "normal" then
+ -- except if it is not_blocking_trains
+ if ndef.groups.not_blocking_trains and ndef.groups.not_blocking_trains ~= 0 then
+ return false
+ end
+ return true
+ end
+ end
+ return false
+ end
+else
+ function advtrains.train_collides(node)
+ if node and minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].walkable then
if not minetest.registered_nodes[node.name].groups.not_blocking_trains then
return true
end
- end
- return false
-end
-
-local nonblocknodes={
- "default:fence_wood",
- "default:fence_acacia_wood",
- "default:fence_aspen_wood",
- "default:fence_pine_wood",
- "default:fence_junglewood",
- "default:torch",
- "bones:bones",
-
- "default:sign_wall",
- "signs:sign_wall",
- "signs:sign_wall_blue",
- "signs:sign_wall_brown",
- "signs:sign_wall_orange",
- "signs:sign_wall_green",
- "signs:sign_yard",
- "signs:sign_wall_white_black",
- "signs:sign_wall_red",
- "signs:sign_wall_white_red",
- "signs:sign_wall_yellow",
- "signs:sign_post",
- "signs:sign_hanging",
-
-
-}
-minetest.after(0, function()
- for _,name in ipairs(nonblocknodes) do
- if minetest.registered_nodes[name] then
- minetest.registered_nodes[name].groups.not_blocking_trains=1
end
+ return false
end
-end)
+
+ local nonblocknodes={
+ "default:fence_wood",
+ "default:fence_acacia_wood",
+ "default:fence_aspen_wood",
+ "default:fence_pine_wood",
+ "default:fence_junglewood",
+ "default:torch",
+ "bones:bones",
+
+ "default:sign_wall",
+ "signs:sign_wall",
+ "signs:sign_wall_blue",
+ "signs:sign_wall_brown",
+ "signs:sign_wall_orange",
+ "signs:sign_wall_green",
+ "signs:sign_yard",
+ "signs:sign_wall_white_black",
+ "signs:sign_wall_red",
+ "signs:sign_wall_white_red",
+ "signs:sign_wall_yellow",
+ "signs:sign_post",
+ "signs:sign_hanging",
+
+ }
+ minetest.after(0, function()
+ for _,name in ipairs(nonblocknodes) do
+ if minetest.registered_nodes[name] then
+ minetest.registered_nodes[name].groups.not_blocking_trains=1
+ end
+ end
+ end)
+end
diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua
index e9b6d7a..fe1a0f8 100644
--- a/advtrains/wagons.lua
+++ b/advtrains/wagons.lua
@@ -413,13 +413,38 @@ function wagon:on_step(dtime)
end
-- Calculate new position, yaw and direction vector
+ -- note: "index" is needed to be the center index, required by door code
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
- local pos, yaw, npos, npos2 = advtrains.path_get_interpolated(train, index)
- local vdir = vector.normalize(vector.subtract(npos2, npos))
+ local pos, yaw, npos, npos2, vdir
+
+ -- use new position logic?
+ if self.wheel_positions then
+ -- request two positions, calculate difference and yaw from this
+ -- depending on flipstate, need to invert wheel pos indices -> wheelpos * fct
+ local index1 = advtrains.path_get_index_by_offset(train, index, self.wheel_positions[1] * fct)
+ local index2 = advtrains.path_get_index_by_offset(train, index, self.wheel_positions[2] * fct)
+ local pos1 = advtrains.path_get_interpolated(train, index1)
+ local pos2 = advtrains.path_get_interpolated(train, index2)
+ npos = advtrains.path_get(train, atfloor(index)) -- need npos just for node loaded check
+ -- calculate center of 2 positions and vdir vector
+ -- if wheel positions are asymmetric, needs to weight by the difference!
+ local fact = self.wheel_positions[1] / (self.wheel_positions[1]-self.wheel_positions[2])
+ pos = {x=pos1.x-(pos1.x-pos2.x)*fact, y=pos1.y-(pos1.y-pos2.y)*fact, z=pos1.z-(pos1.z-pos2.z)*fact}
+ if data.wagon_flipped then
+ vdir = vector.normalize(vector.subtract(pos2, pos1))
+ else
+ vdir = vector.normalize(vector.subtract(pos1, pos2))
+ end
+ yaw = math.atan2(-vdir.x, vdir.z)
+ else
+ --old position logic (for small wagons): use center index and just get position
+ pos, yaw, npos, npos2 = advtrains.path_get_interpolated(train, index)
+ vdir = vector.normalize(vector.subtract(npos2, npos))
+ end
--automatic get_on
--needs to know index and path
- if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 then
+ if train.velocity==0 and self.door_entry and train.door_open and train.door_open~=0 then
--using the mapping created by the trainlogic globalstep
for i, ino in ipairs(self.door_entry) do
--fct is the flipstate flag from door animation above
@@ -470,28 +495,32 @@ function wagon:on_step(dtime)
end
end
- --DisCouple
+ -- Spawn discouple object when train stands, in all other cases remove it.
-- FIX: Need to do this after the yaw calculation
- if is_in_loaded_area and data.pos_in_trainparts and data.pos_in_trainparts>1 then
- if train.velocity==0 then
- if not self.discouple or not self.discouple.object:get_yaw() then
- atprint(self.id,"trying to spawn discouple")
- local dcpl_pos = vector.add(pos, {y=0, x=-math.sin(yaw)*self.wagon_span, z=math.cos(yaw)*self.wagon_span})
- local object=minetest.add_entity(dcpl_pos, "advtrains:discouple")
- if object then
- local le=object:get_luaentity()
- le.wagon=self
- --box is hidden when attached, so unuseful.
- --object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0})
- self.discouple=le
- end
- end
- else
- if self.discouple and self.discouple.object:get_yaw() then
- self.discouple.object:remove()
- atprint(self.id," removing discouple")
+ if train.velocity==0 and is_in_loaded_area and data.pos_in_trainparts and data.pos_in_trainparts>1 then
+ if not self.discouple or not self.discouple.object:get_yaw() then
+ atprint(self.id,"trying to spawn discouple")
+ local dcpl_pos = vector.add(pos, {y=0, x=-math.sin(yaw)*self.wagon_span, z=math.cos(yaw)*self.wagon_span})
+ local object=minetest.add_entity(dcpl_pos, "advtrains:discouple")
+ if object then
+ local le=object:get_luaentity()
+ le.wagon=self
+ --box is hidden when attached, so unuseful.
+ --object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0})
+ self.discouple=le
end
end
+ else
+ if self.discouple and self.discouple.object:get_yaw() then
+ self.discouple.object:remove()
+ atprint(self.id," removing discouple")
+ end
+ end
+
+ -- object yaw (corrected by flipstate)
+ local oyaw = yaw
+ if data.wagon_flipped then
+ oyaw = yaw + math.pi
end
--FIX: use index of the wagon, not of the train.
@@ -500,10 +529,6 @@ function wagon:on_step(dtime)
local velocityvec = vector.multiply(vdir, velocity)
local accelerationvec = vector.multiply(vdir, acceleration)
- if data.wagon_flipped then
- yaw=yaw+math.pi
- end
-
-- this timer runs off every 2 seconds.
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
local updatepct_timer_elapsed = self.updatepct_timer<=0
@@ -540,19 +565,19 @@ function wagon:on_step(dtime)
or not vector.equals(velocityvec, self.old_velocity_vector)
or not self.old_acceleration_vector
or not vector.equals(accelerationvec, self.old_acceleration_vector)
- or self.old_yaw~=yaw
+ or self.old_yaw~=oyaw
or updatepct_timer_elapsed then--only send update packet if something changed
self.object:set_pos(pos)
self.object:set_velocity(velocityvec)
self.object:set_acceleration(accelerationvec)
- if #self.seats > 0 and self.old_yaw ~= yaw then
+ if #self.seats > 0 and self.old_yaw ~= oyaw then
if not self.player_yaw then
self.player_yaw = {}
end
if not self.old_yaw then
- self.old_yaw=yaw
+ self.old_yaw=oyaw
end
for _,name in pairs(data.seatp) do
local p = minetest.get_player_by_name(name)
@@ -562,11 +587,11 @@ function wagon:on_step(dtime)
self.player_yaw[name] = p:get_look_horizontal()-self.old_yaw
end
-- set player looking direction using calculated offset
- p:set_look_horizontal((self.player_yaw[name] or 0)+yaw)
+ p:set_look_horizontal((self.player_yaw[name] or 0)+oyaw)
end
end
self.turning = true
- elseif self.old_yaw == yaw then
+ elseif self.old_yaw == oyaw then
-- train is no longer turning
self.turning = false
end
@@ -576,9 +601,9 @@ function wagon:on_step(dtime)
if data.wagon_flipped then
pitch = -pitch
end
- self.object:set_rotation({x=pitch, y=yaw, z=0})
+ self.object:set_rotation({x=pitch, y=oyaw, z=0})
else
- self.object:set_yaw(yaw)
+ self.object:set_yaw(oyaw)
end
if self.update_animation then
@@ -597,7 +622,7 @@ function wagon:on_step(dtime)
self.old_velocity_vector=velocityvec
self.old_velocity = train.velocity
self.old_acceleration_vector=accelerationvec
- self.old_yaw=yaw
+ self.old_yaw=oyaw
atprintbm("wagon step", t)
end
@@ -1240,70 +1265,6 @@ function wagon:reattach_all()
end
end
-local function check_twagon_owner(train, b_first, pname)
- local wtp = b_first and 1 or #train.trainparts
- local wid = train.trainparts[wtp]
- local wdata = advtrains.wagons[wid]
- if wdata then
- return advtrains.check_driving_couple_protection(pname, wdata.owner, wdata.whitelist)
- end
- return false
-end
-
-function advtrains.safe_couple_trains(id1, id2, t1f, t2f, pname, try_run,v1,v2)
-
- if pname and not minetest.check_player_privs(pname, "train_operator") then
- minetest.chat_send_player(pname, "Missing train_operator privilege")
- return false
- end
-
- local train1=advtrains.trains[id1]
- local train2=advtrains.trains[id2]
-
- if not advtrains.train_ensure_init(id1, train1)
- or not advtrains.train_ensure_init(id2, train2) then
- return false
- end
- local wck_t1, wck_t2
- if pname then
- wck_t1 = check_twagon_owner(train1, t1f, pname)
- wck_t2 = check_twagon_owner(train2, t2f, pname)
- end
- if (wck_t1 or wck_t2) or not pname then
- if not v1 then
- v1 = 0
- end
- if not v2 then
- v2 = 0
- end
- if try_run then
- return true
- end
- if t1f then
- if t2f then
- v1 = -v1
- advtrains.invert_train(id1)
- advtrains.do_connect_trains(id1, id2, v1+v2)
- else
- advtrains.do_connect_trains(id2, id1, v1+v2)
- end
- else
- if t2f then
- advtrains.do_connect_trains(id1, id2, v1+v2)
- else
- v2 = -v2
- advtrains.invert_train(id2)
- advtrains.do_connect_trains(id1, id2, v1+v2)
- end
- end
- return true
- else
- minetest.chat_send_player(pname, "You must be authorized for at least one wagon.")
- return false
- end
-end
-
-
function advtrains.safe_decouple_wagon(w_id, pname, try_run)
if not minetest.check_player_privs(pname, "train_operator") then
minetest.chat_send_player(pname, "Missing train_operator privilege")
@@ -1380,14 +1341,23 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
minetest.register_entity(":"..sysname,prototype)
advtrains.wagon_prototypes[sysname] = prototype
+ --group classification to make recipe searching easier
+ local wagon_groups = { not_in_creative_inventory = nincreative and 1 or 0}
+ if prototype.is_locomotive then wagon_groups['at_loco'] = 1 end
+ if prototype.seat_groups then
+ if prototype.seat_groups.dstand then wagon_groups['at_control'] = 1 end
+ if prototype.seat_groups.pass then wagon_groups['at_pax'] = 1 end
+ end
+ if prototype.has_inventory then wagon_groups['at_freight'] = 1 end
+
minetest.register_craftitem(":"..sysname, {
description = desc,
inventory_image = inv_img,
wield_image = inv_img,
stack_max = 1,
- groups = { not_in_creative_inventory = nincreative and 1 or 0},
-
+ groups = wagon_groups,
+
on_place = function(itemstack, placer, pointed_thing)
if not pointed_thing.type == "node" then
return
diff --git a/advtrains_interlocking/README.md b/advtrains_interlocking/README.md
new file mode 100644
index 0000000..d4a2699
--- /dev/null
+++ b/advtrains_interlocking/README.md
@@ -0,0 +1,85 @@
+# Interlocking for Advtrains
+
+The `advtrains_interlocking` mod provides various interlocking and signaling features for Advtrains.
+
+## Signal aspect tables
+
+Signal aspects are represented using tables with the following (optional) fields:
+
+* `main`: The main signal aspect. It provides information on the permitted speed after passing the signal.
+* `dst`: The distant signal aspect. It provides information on the permitted speed after passing the next signal.
+* `shunt`: Whether the train may proceed in shunt mode and, if the main aspect is danger, proceed in shunt mode.
+* `proceed_as_main`: Whether the train should exit shunt mode when proceeding.
+* `group`: The name of the signal group.
+* `name`: The name of the signal aspect.
+
+The `main` and `dst` fields may be:
+
+* An positive number indicating the permitted speed,
+* The number 0, indicating that the train should expect to stop at the current signal (or, for the `dst` field, the next signal),
+* The number -1, indicating that the train can proceed (or, for the `dst` field, expect to proceed) at maximum speed,
+* The constant `false`, indicating no change to the speed restriction, or
+* The constant `nil`, indicating that the default value for the name aspect (if present) is used. If no valid signal aspect is named, or the signal aspect does not provide a default value, the value is assumed to be `false`.
+
+### Node definitions
+
+Signals should belong the following node groups:
+
+* `advtrains_signal`: `1` for static signals, `2` for signals with variable aspects.
+* `save_in_at_nodedb`: This should be set to `1` to make sure that Advtrains always has access to the signal.
+* `not_blocking_trains`: Setting this to `1` prevents trains from colliding with the signal. Setting this is not necessary, but recommended.
+
+The node definition should contain an `advtrains` field.
+
+The `advtrains` field of the node definition should contain a `supported_aspects` table for signals with variable aspects.
+
+The `supported_aspects` table should contain the following fields:
+
+* `main`: A list of values supported for the main aspect.
+* `dst`: A list of values supported for the distant aspect.
+* `shunt`: The value for the `shunt` field of the signal aspect or `nil` if the value is variable.
+* `proceed_as_main`: The value for the `proceed_as_main` field of the signal aspect.
+* `group`: The name of the signal group.
+* `name`: A list of supported (named) aspects.
+* `dst_shift`: The phase shift for distant/repeater signals. This field should not be set for main signals.
+
+The `advtrains` field of the node definition should contain a `get_aspect` function. This function is given the position of the signal and the node at the position. It should return the signal aspect table or, in the case of type 2 signals, the name of the signal aspect.
+
+For signals with variable aspects, a corresponding `set_aspect` function should also be defined. This function is given the position of the signal, the node at the position, and the new aspect. The new aspect is not guaranteed to be supported by the signal itself.
+
+Signals should also have the following callbacks set:
+
+* `on_rightclick` should be set to `advtrains.interlocking.signal_rc_handler`
+* `can_dig` should be set to `advtrains.interlocking.signal_can_dig`
+* `after_dig_node` should be set to `advtrains.interlocking.signal_after_dig`
+
+Alternatively, custom callbacks should call the respective functions.
+
+## Signal groups
+
+Signals may belong to signal groups are registered using `advtrains.interlocking.aspect.register_group`.
+
+Signal group definitions include the following fields:
+
+* `name`: The internal name of the signal group. It is recommended to use the mod name as a prefix to avoid name collisions.
+* `label`: The description of the signal group.
+* `aspects`: A table of signal aspects. Entries with string indices define the signal aspect with the name. Entries with numeric indices (starting from 1, counting upward) contain a list of corresponding aspect names (the first entry is preferred) and are mainly used for routing, where larger indices indicate that the signal with the aspect is closer to the signal with the "danger" (or similar) aspect.
+
+Each aspect in the signal group definition table should contain the following fields:
+
+* `label`: The description of the signal aspect.
+* `main`, `shunt`, `proceed_as_main`: The default values for the aspect. Note that the `dst` field has no default value as it is automatically adjusted.
+
+## Notes
+
+It is allowed to provide other methods of setting the signal aspect. However:
+
+* These changes are ignored by the routesetting system.
+* Please call `advtrains.interlocking.signal_readjust_aspect` after the signal aspect has changed.
+
+## Examples
+An example of speed signals can be found in `advtrains_signals_ks`, which provides a subset of German signals.
+
+An example of route signals can be found in `advtrains_signals_japan`, which provides a subset of Japanese signals.
+
+The mods mentioned above are also used for demonstation purposes and can also be used for testing.
diff --git a/advtrains_interlocking/approach.lua b/advtrains_interlocking/approach.lua
index f60468a..eecf09a 100644
--- a/advtrains_interlocking/approach.lua
+++ b/advtrains_interlocking/approach.lua
@@ -14,19 +14,19 @@ local SHUNT_SPEED_MAX = advtrains.SHUNT_SPEED_MAX
local il = advtrains.interlocking
-local function get_over_function(speed, shunt)
+local function get_over_function(speed, shunt, asptype)
return function(pos, id, train, index, speed, lzbdata)
if speed == 0 and minetest.settings:get_bool("at_il_force_lzb_halt") then
atwarn(id,"overrun LZB 0 restriction (red signal) ",pos)
-- Set train 1 index backward. Hope this does not lead to bugs...
--train.index = index - 0.5
- train.speed_restriction = 0
+ advtrains.speed.set_restriction(train, "main", 0)
--TODO temporary
--advtrains.drb_dump(id)
--error("Debug: "..id.." triggered LZB-0")
else
- train.speed_restriction = speed
+ advtrains.speed.set_restriction(train, asptype, speed or -1)
train.is_shunt = shunt
end
--atdebug("train drove over IP: speed=",speed,"shunt=",shunt)
@@ -94,6 +94,7 @@ advtrains.tnc_register_on_approach(function(pos, id, train, index, has_entered,
end
-- nspd can now be: 1. !=0: new speed restriction, 2. =0: stop here or 3. nil: keep travspd
if nspd then
+ travspd = nspd
if nspd == -1 then
travspd = nil
else
@@ -106,7 +107,7 @@ advtrains.tnc_register_on_approach(function(pos, id, train, index, has_entered,
lspd = travspd
local udata = {signal_pos = spos}
- local callback = get_over_function(lspd, travsht)
+ local callback = get_over_function(lspd, travsht, asp.type)
lzbdata.il_shunt = travsht
lzbdata.il_speed = travspd
--atdebug("new lzbdata",lzbdata)
diff --git a/advtrains_interlocking/ars.lua b/advtrains_interlocking/ars.lua
index 434ae2c..4f50df9 100644
--- a/advtrains_interlocking/ars.lua
+++ b/advtrains_interlocking/ars.lua
@@ -133,9 +133,11 @@ function advtrains.interlocking.ars_check(sigd, train)
local tcbs = il.db.get_tcbs(sigd)
if not tcbs or not tcbs.routes then return end
- if tcbs.ars_disabled then
+ if tcbs.ars_disabled or tcbs.ars_ignore_next then
-- No-ARS mode of signal.
-- ignore...
+ -- Note: ars_ignore_next is set by signalling formspec when route is cancelled
+ tcbs.ars_ignore_next = nil
return
end
diff --git a/advtrains_interlocking/aspect.lua b/advtrains_interlocking/aspect.lua
new file mode 100644
index 0000000..c7d5c81
--- /dev/null
+++ b/advtrains_interlocking/aspect.lua
@@ -0,0 +1,296 @@
+--- Signal aspect handling.
+-- @module advtrains.interlocking.aspect
+
+local registered_groups = {}
+
+local default_aspect = {
+ main = false,
+ dst = false,
+ shunt = true,
+ proceed_as_main = false,
+}
+
+local signal_aspect = {}
+
+local signal_aspect_metatable = {
+ __eq = function(asp1, asp2)
+ for _, k in pairs {"main", "dst", "shunt", "proceed_as_main"} do
+ local v1, v2 = (asp1[k] or false), (asp2[k] or false)
+ if v1 ~= v2 then
+ return false
+ end
+ end
+ if asp1.group and asp1.group == asp2.group then
+ return asp1.name == asp2.name
+ end
+ return true
+ end,
+ __index = function(asp, field)
+ local val = signal_aspect[field]
+ if val then
+ return val
+ end
+ val = default_aspect[field]
+ if val == nil then
+ return nil
+ end
+ local group = registered_groups[rawget(asp, "group")]
+ if group then
+ local aspdef = group.aspects[rawget(asp, "name")]
+ if aspdef[field] ~= nil then
+ val = aspdef[field]
+ end
+ end
+ return val
+ end,
+ __tostring = function(asp)
+ local st = {}
+ if asp.group and asp.name then
+ table.insert(st, ("%q in %q"):format(asp.name, asp.group))
+ end
+ if asp.main then
+ table.insert(st, ("current %d"):format(asp.main))
+ end
+ if asp.main ~= 0 then
+ if asp.dst then
+ table.insert(st, string.format("next %d", asp.dst))
+ end
+ end
+ if asp.main ~= 0 and asp.proceed_as_main then
+ table.insert(st, "proceed as main")
+ end
+ return ("[%s]"):format(table.concat(st, ", "))
+ end,
+}
+
+local function quicknew(t)
+ return setmetatable(t, signal_aspect_metatable)
+end
+
+--- Signal aspect class.
+-- @type signal_aspect
+
+--- Return a plain version of the signal aspect.
+-- @param[opt=false] raw Bypass metamethods when fetching signal aspects
+-- @return A plain copy of the signal aspect object.
+function signal_aspect:plain(raw)
+ local t = {}
+ for _, k in pairs {"main", "dst", "shunt", "proceed_as_main", "group", "name"} do
+ local v
+ if raw then
+ v = rawget(self, k)
+ else
+ v = self[k]
+ end
+ t[k] = v
+ end
+ return t
+end
+
+--- Create (or copy) a signal aspect object.
+-- Note that signal aspect objects can also be created by calling the `advtrains.interlocking.aspect` table.
+-- @return The newly created signal aspect object.
+function signal_aspect:new()
+ if type(self) ~= "table" then
+ return quicknew{}
+ end
+ local newasp = {}
+ for _, k in pairs {"main", "dst"} do
+ if type(self[k]) == "table" then
+ if self[k].free then
+ newasp[k] = self[k].speed
+ else
+ newasp[k] = 0
+ end
+ else
+ newasp[k] = self[k]
+ end
+ end
+ if type(self.shunt) == "table" then
+ newasp.shunt = self.shunt.free
+ newasp.proceed_as_main = self.shunt.proceed_as_main
+ else
+ newasp.shunt = self.shunt
+ end
+ for _, k in pairs {"group", "name"} do
+ newasp[k] = self[k]
+ end
+ return quicknew(newasp)
+end
+
+--- Modify the signal aspect in-place to fit in the specific signal group.
+-- @param group The signal group. The `nil` indicates a generic group.
+-- @return The (now modified) signal aspect itself.
+function signal_aspect:to_group(group)
+ local cg = self.group
+ local gdef = registered_groups[group]
+ if type(self.name) ~= "string" then
+ self.name = nil
+ end
+ if not gdef then
+ for k in pairs(default_aspect) do
+ rawset(self, k, self[k])
+ end
+ self.group = nil
+ self.name = nil
+ return self
+ elseif cg == group and gdef.aspects[self.name] then
+ return self
+ end
+ local newidx = 1
+ if self.main == 0 then
+ newidx = #gdef.aspects
+ end
+ local cgdef = registered_groups[cg]
+ if cgdef then
+ local idx = (cgdef.aspects[self.name] or {}).index
+ if idx then
+ if idx >= #cgdef.aspects then
+ idx = #gdef.aspects
+ elseif idx >= #gdef.aspects then
+ idx = #gdef.aspects-1
+ end
+ newidx = idx
+ end
+ end
+ self.group = group
+ self.name = gdef.aspects[newidx][1]
+ return self
+end
+
+--- Modify the signal aspect in-place to indicate a specific distant aspect.
+-- @param dst The distant aspect
+-- @param[opt=1] shift The phase shift of the current signal.
+-- @return The (now modified) signal aspect itself.
+function signal_aspect:adjust_distant(dst, shift)
+ if (shift or -1) < 0 then
+ shift = 1
+ end
+ if not dst then
+ self.dst = nil
+ return self
+ end
+ if self.main ~= 0 then
+ self.dst = dst.main
+ else
+ self.dst = nil
+ return self
+ end
+ local dgdef = registered_groups[dst.group]
+ if dgdef then
+ if self.group == dst.group and shift == 0 then
+ self.name = dst.name
+ else
+ local idx = (dgdef.aspects[dst.name] or {}).index
+ if idx then
+ idx = math.max(idx-shift, 1)
+ self.group = dst.group
+ self.name = dgdef.aspects[idx][1]
+ end
+ end
+ end
+ return self
+end
+
+--- Signal groups.
+-- @section signal_group
+
+--- Register a signal group.
+-- @function register_group
+-- @param def The definition table.
+local function register_group(def)
+ local t = {}
+ local name = def.name
+ if type(name) ~= "string" then
+ return error("Expected signal group name to be a string, got " .. type(name))
+ elseif registered_groups[name] then
+ return error(string.format("Attempt to redefine signal group %q, previously defined in %s", name, registered_groups[name].defined))
+ end
+ t.name = name
+
+ t.defined = debug.getinfo(2, "S").short_src or "[?]"
+
+ local label = def.label or name
+ if type(label) ~= "string" then
+ return error("Label is not a string")
+ end
+ t.label = label
+
+ local mainasps = {}
+ for idx, asp in pairs(def.aspects) do
+ local idxtp = type(idx)
+ if idxtp == "string" then
+ local t = {}
+ t.name = idx
+
+ local label = asp.label or idx
+ if type(label) ~= "string" then
+ return error("Aspect label is not a string")
+ end
+ t.label = label
+
+ for _, k in pairs{"main", "dst", "shunt"} do
+ t[k] = asp[k]
+ end
+
+ mainasps[idx] = t
+ end
+ end
+ if #def.aspects < 2 then
+ return error("Insufficient entries in signal aspect list")
+ end
+ for idx, asplist in ipairs(def.aspects) do
+ if type(asplist) ~= "table" then
+ asplist = {asplist}
+ else
+ asplist = table.copy(asplist)
+ end
+ if #asplist < 1 then
+ error("Invalid entry in signal aspect list")
+ end
+ for _, k in ipairs(asplist) do
+ if type(k) ~= "string" then
+ return error("Invalid signal aspect ID")
+ end
+ local asp = mainasps[k]
+ if not asp then
+ return error("Invalid signal aspect ID")
+ end
+ if asp.index ~= nil then
+ return error("Attempt to assign a signal aspect to multiple numeric indices")
+ end
+ asp.index = idx
+ end
+ mainasps[idx] = asplist
+ end
+ t.aspects = mainasps
+
+ registered_groups[name] = t
+end
+
+--- Get the definition of a signal group.
+-- @function get_group_definition
+-- @param name The name of the signal group.
+-- @return[1] The definition for the signal group (if present).
+-- @return[2] The nil constant (otherwise).
+local function get_group_definition(name)
+ local t = registered_groups[name]
+ if t then
+ return table.copy(t)
+ else
+ return nil
+ end
+end
+
+local lib = {
+ register_group = register_group,
+ get_group_definition = get_group_definition,
+}
+
+local libmt = {
+ __call = function(_, ...)
+ return signal_aspect.new(...)
+ end,
+}
+
+return setmetatable(lib, libmt)
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index ee21db9..c5ae906 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -131,6 +131,12 @@ function ildb.load(data)
if data.npr_rails then
advtrains.interlocking.npr_rails = data.npr_rails
end
+ if data.supposed_aspects then
+ advtrains.interlocking.load_supposed_aspects(data.supposed_aspects)
+ end
+ if data.distant then
+ advtrains.distant.load(data.distant)
+ end
--COMPATIBILITY to Signal aspect format
-- TODO remove in time...
@@ -173,6 +179,8 @@ function ildb.save()
rs_callbacks = advtrains.interlocking.route.rte_callbacks,
influence_points = influence_points,
npr_rails = advtrains.interlocking.npr_rails,
+ supposed_aspects = advtrains.interlocking.save_supposed_aspects(),
+ distant = advtrains.distant.save(),
}
end
@@ -195,8 +203,6 @@ TCB data structure
signal_name = <string> -- The human-readable name of the signal, only for documenting purposes
routes = { <route definition> } -- a collection of routes from this signal
route_auto = <boolean> -- When set, we will automatically re-set the route (designated by routeset)
- distant = { <sigd1> ... } -- a collection of sigd that points to a side of a TCB with a distant signal for this current signal.
- distant_of = { <sigd>, <index> } -- the reverse of the above field, along with the index of the entry in the list (for easier lookup)
},
-- This is the "B" side of the TCB
[2] = { -- Variant: end of track-circuited area (initial state of TC)
@@ -636,6 +642,28 @@ function ildb.get_ip_by_signalpos(spos)
end
end
end
+function ildb.check_for_duplicate_ip(spos)
+ local main_ip_found = false
+ -- first pass: check for duplicates
+ for pts,tab in pairs(influence_points) do
+ for connid,pos in pairs(tab) do
+ if vector.equals(pos, spos) then
+ if main_ip_found then
+ atwarn("Signal at",spos,": Deleting duplicate signal influence point at",pts,"/",connid)
+ tab[connid] = nil
+ end
+ main_ip_found = true
+ end
+ end
+ end
+ -- second pass: delete empty tables
+ for pts,tab in pairs(influence_points) do
+ if not tab[1] and not tab[2] then -- only those two connids may exist
+ influence_points[pts] = nil
+ end
+ end
+end
+
-- clear signal assignment given the signal position
function ildb.clear_ip_by_signalpos(spos)
local pts, connid = ildb.get_ip_by_signalpos(spos)
diff --git a/advtrains_interlocking/demosignals.lua b/advtrains_interlocking/demosignals.lua
index 1c1b8b2..de6926a 100644
--- a/advtrains_interlocking/demosignals.lua
+++ b/advtrains_interlocking/demosignals.lua
@@ -50,7 +50,7 @@ minetest.register_node("advtrains_interlocking:ds_danger", {
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
- after_dig_node = advtrains.interlocking.signal_after_dig,
+ after_destruct = advtrains.interlocking.signal_after_dig,
})
minetest.register_node("advtrains_interlocking:ds_free", {
description = "Demo signal at Free",
@@ -71,7 +71,7 @@ minetest.register_node("advtrains_interlocking:ds_free", {
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
- after_dig_node = advtrains.interlocking.signal_after_dig,
+ after_destruct = advtrains.interlocking.signal_after_dig,
})
minetest.register_node("advtrains_interlocking:ds_slow", {
description = "Demo signal at Slow",
@@ -92,6 +92,6 @@ minetest.register_node("advtrains_interlocking:ds_slow", {
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
- after_dig_node = advtrains.interlocking.signal_after_dig,
+ after_destruct = advtrains.interlocking.signal_after_dig,
})
diff --git a/advtrains_interlocking/distant.lua b/advtrains_interlocking/distant.lua
new file mode 100644
index 0000000..32ada82
--- /dev/null
+++ b/advtrains_interlocking/distant.lua
@@ -0,0 +1,200 @@
+--- Distant signaling.
+-- This module implements a database backend for distant signal assignments.
+-- The actual modifications to signal aspects are still done by signal aspect accessors.
+-- @module advtrains.interlocking.distant
+
+local db_distant = {}
+local db_distant_of = {}
+
+local pts = advtrains.encode_pos
+local stp = advtrains.decode_pos
+
+--- Replace the distant signal assignment database.
+-- @function load
+-- @param db The new database to load.
+local function db_load(x)
+ if type(x) ~= "table" then
+ return
+ end
+ db_distant = x.distant
+ db_distant_of = x.distant_of
+end
+
+--- Retrieve the current distant signal assignment database.
+-- @function save
+-- @return The current database.
+local function db_save()
+ return {
+ distant = db_distant,
+ distant_of = db_distant_of,
+ }
+end
+
+local update_signal, update_main, update_dst
+
+--- Unassign a distant signal.
+-- @function unassign_dst
+-- @param dst The position of the distant signal.
+-- @param[opt=false] force Whether to skip callbacks.
+local function unassign_dst(dst, force)
+ local pts_dst = pts(dst)
+ local main = db_distant_of[pts_dst]
+ db_distant_of[pts_dst] = nil
+ if main then
+ local pts_main = main[1]
+ local t = db_distant[pts_main]
+ if t then
+ t[pts_dst] = nil
+ end
+ end
+ if not force then
+ update_dst(dst)
+ end
+end
+
+--- Unassign a main signal.
+-- @function unassign_main
+-- @param main The position of the main signal.
+-- @param[opt=false] force Whether to skip callbacks.
+local function unassign_main(main, force)
+ local pts_main = pts(main)
+ local t = db_distant[pts_main]
+ if not t then
+ return
+ end
+ for pts_dst in pairs(t) do
+ local realmain = db_distant_of[pts_dst]
+ if realmain and realmain[1] == pts_main then
+ db_distant_of[pts_dst] = nil
+ if not force then
+ local dst = stp(pts_dst)
+ update_dst(dst)
+ end
+ end
+ end
+ db_distant[pts_main] = nil
+end
+
+--- Remove all (main and distant) signal assignments from a signal.
+-- @function unassign_all
+-- @param pos The position of the signal.
+-- @param[opt=false] force Whether to skip callbacks.
+local function unassign_all(pos, force)
+ unassign_main(pos)
+ unassign_dst(pos, force)
+end
+
+--- Check whether a signal is "appropriate" for the distant signal system.
+-- Currently, a signal is considered appropriate if its signal aspect can be set.
+-- @function appropriate_signal
+-- @param pos The position of the signal
+local function appropriate_signal(pos)
+ local node = advtrains.ndb.get_node(pos)
+ local ndef = minetest.registered_nodes[node.name] or {}
+ if not ndef then
+ return false
+ end
+ local atdef = ndef.advtrains
+ if not atdef then
+ return false
+ end
+ return atdef.supported_aspects and atdef.set_aspect and true
+end
+
+--- Assign a distant signal to a main signal.
+-- @function assign
+-- @param main The position of the main signal.
+-- @param dst The position of the distant signal.
+-- @param[opt="manual"] by The method of assignment.
+-- @param[opt=false] skip_update Whether to skip callbacks.
+local function assign(main, dst, by, skip_update)
+ if not (appropriate_signal(main) and appropriate_signal(dst)) then
+ return
+ end
+ local pts_main = pts(main)
+ local pts_dst = pts(dst)
+ local t = db_distant[pts_main]
+ if not t then
+ t = {}
+ db_distant[pts_main] = t
+ end
+ if not by then
+ by = "manual"
+ end
+ unassign_dst(dst, true)
+ t[pts_dst] = by
+ db_distant_of[pts_dst] = {pts_main, by}
+ if not skip_update then
+ update_dst(dst)
+ end
+end
+
+--- Get the distant signals assigned to a main signal.
+-- @function get_distant
+-- @param main The position of the main signal.
+-- @treturn {[pos]=by,...} A table of distant signals, with the positions encoded using `advtrains.encode_pos`.
+local function get_distant(main)
+ local pts_main = pts(main)
+ return db_distant[pts_main] or {}
+end
+
+--- Get the main signal assigned the a distant signal.
+-- @function get_main
+-- @param dst The position of the distant signal.
+-- @return The position of the main signal.
+-- @return The method of assignment.
+local function get_main(dst)
+ local pts_dst = pts(dst)
+ local main = db_distant_of[pts_dst]
+ if not main then
+ return
+ end
+ if main[1] then
+ return stp(main[1]), unpack(main, 2)
+ else
+ return unpack(main)
+ end
+end
+
+--- Update all distant signals assigned to a main signal.
+-- @function update_main
+-- @param main The position of the main signal.
+update_main = function(main)
+ local pts_main = pts(main)
+ local t = get_distant(main)
+ for pts_dst in pairs(t) do
+ local dst = stp(pts_dst)
+ advtrains.interlocking.signal_readjust_aspect(dst)
+ end
+end
+
+--- Update the aspect of a distant signal.
+-- @function update_dst
+-- @param dst The position of the distant signal.
+update_dst = function(dst)
+ advtrains.interlocking.signal_readjust_aspect(dst)
+end
+
+--- Update the aspect of a combined (main and distant) signal and all distant signals assigned to it.
+-- @function update_signal
+-- @param pos The position of the signal.
+update_signal = function(pos)
+ update_main(pos)
+ update_dst(pos)
+end
+
+advtrains.distant = {
+ load = db_load,
+ save = db_save,
+ assign = assign,
+ unassign_dst = unassign_dst,
+ unassign_main = unassign_main,
+ unassign_all = unassign_all,
+ get_distant = get_distant,
+ get_dst = get_distant,
+ get_main = get_main,
+ update_main = update_main,
+ update_dst = update_dst,
+ update_signal = update_signal,
+ appropriate_signal = appropriate_signal,
+}
diff --git a/advtrains_interlocking/distant_signals.lua b/advtrains_interlocking/distant_signals.lua
deleted file mode 100644
index 0da1c10..0000000
--- a/advtrains_interlocking/distant_signals.lua
+++ /dev/null
@@ -1,83 +0,0 @@
-local interlocking = advtrains.interlocking
-local ildb = advtrains.interlocking.db
-
-local function update_distant(tcbs)
- if not (tcbs and tcbs.signal) then return end
- if not tcbs.aspect then tcbs.aspect = table.copy(interlocking.DANGER) end
- local asp = tcbs.aspect
- if tcbs.distant_of then
- asp.dst = (ildb.get_tcbs(tcbs.distant_of[1]).aspect or interlocking.DANGER).main
- end
- interlocking.update_signal_aspect(tcbs)
- if tcbs.distant then
- local dst = tcbs.distant
- for i = 1, #dst do
- local s = ildb.get_tcbs(dst[i])
- if not s.aspect then s.aspect = table.copy(interlocking.DANGER) end
- s.aspect.dst = asp.main
- interlocking.update_signal_aspect(s)
- end
- end
-end
-
-local function unassign_distant(dsts)
- if not dsts then return end
- local dof = dsts.distant_of
- if not dof then return end
- if dsts.signal and dsts.aspect then
- dsts.aspect.dst = nil
- interlocking.update_signal_aspect(dsts)
- end
- local sigd, idx = dof[1], dof[2]
- local tcbs = ildb.get_tcbs(sigd)
- local dst = tcbs.distant
- dsts.distant_of = nil
- if idx == #dst then
- dst[#dst] = nil
- else
- local ent = dst[#dst]
- dst[idx] = ent
- dst[#dst] = nil
- local repl = ildb.get_tcbs(ent)
- repl.distant_of[2] = idx
- end
-end
-
-local function assign_distant(sigd, dstd)
- if not sigd then return end
- if not dstd then return end
- local tcbs = ildb.get_tcbs(sigd)
- local dsts = ildb.get_tcbs(dstd)
- unassign_distant(dsts)
- if not (tcbs.signal and dsts.signal) then return end
- local dst = tcbs.distant
- if not dst then
- dst = {}
- tcbs.distant = dst
- end
- local newidx = #dst+1
- dsts.distant_of = {sigd, newidx}
- dst[newidx] = dstd
- update_distant(dsts)
-end
-
-local function remove_distant(tcbs)
- if not tcbs then return end
- if tcbs.distant_of then
- unassign_distant(tcbs)
- end
- if tcbs.distant then
- local dst = tcbs.distant
- for i = #dst, 1, -1 do
- local s = ildb.get_tcbs(dst[i])
- unassign_distant(s)
- end
- end
-end
-
-interlocking.distant = {
- assign = assign_distant,
- unassign = unassign_distant,
- remove = remove_distant,
- update = update_distant,
-}
diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua
new file mode 100644
index 0000000..bb66dc4
--- /dev/null
+++ b/advtrains_interlocking/distant_ui.lua
@@ -0,0 +1,141 @@
+local F = advtrains.formspec
+local D = advtrains.distant
+local I = advtrains.interlocking
+
+function I.make_short_dst_formspec_component(pos, x, y, w)
+ local main, set_by = D.get_main(pos)
+ if main then
+ local pts_main = minetest.pos_to_string(main)
+ local desc = attrans("The assignment is made with an unknown method.")
+ if set_by == "manual" then
+ desc = attrans("The assignment is made manually.")
+ elseif set_by == "routesetting" then
+ desc = attrans("The assignment is made by the routesetting system.")
+ end
+ return table.concat {
+ F.S_label(x, y, "This signal is a distant signal of @1.", pts_main),
+ F.label(x, y+0.5, desc),
+ F.S_button_exit(x, y+1, w/2-0.125, "dst_assign", "Reassign"),
+ F.S_button_exit(x+w/2+0.125, y+1, w/2-0.125, "dst_unassign", "Unassign"),
+ }
+ else
+ return table.concat {
+ F.S_label(x, y, "This signal is not assigned to a main signal."),
+ F.S_label(x, y+0.5, "The distant aspect of the signal is not used."),
+ F.S_button_exit(x, y+1, w, "dst_assign", "Assign")
+ }
+ end
+end
+
+function I.make_dst_list_formspec_component(pos, x, y, w, h)
+ local ymid = y+0.25+h/2
+ local dstlist = {}
+ for pos, _ in pairs(D.get_dst(pos)) do
+ table.insert(dstlist, minetest.pos_to_string(advtrains.decode_pos(pos)))
+ end
+ return table.concat {
+ F.S_label(x, y, "Distant signals:"),
+ F.textlist(x, y+0.5, w-1, h-0.5, "dstlist", dstlist),
+ F.image_button_exit(x+w-0.75, ymid-0.875, 0.75, 0.75, "cdb_add.png", "dst_add", ""),
+ F.image_button_exit(x+w-0.75, ymid+0.125, 0.75, 0.75, "cdb_clear.png", "dst_del", ""),
+ }
+end
+
+function I.make_dst_formspec_component(pos, x, y, w, h)
+ return I.make_short_dst_formspec_component(pos, x, y, w, h)
+ .. I.make_dst_list_formspec_component(pos, x, y+2, w, h-2)
+end
+
+function I.show_distant_signal_form(pos, pname)
+ return I.show_ip_form(pos, pname)
+end
+
+local signal_pos = {}
+local function init_signal_assignment(pname, pos)
+ if not minetest.check_player_privs(pname, "interlocking") then
+ minetest.chat_send_player(pname, attrans("This operation is not allowed without the @1 privilege.", "interlocking"))
+ return
+ end
+ if not D.appropriate_signal(pos) then
+ minetest.chat_send_player(pname, attrans("Incompatible signal."))
+ return
+ end
+ signal_pos[pname] = pos
+ minetest.chat_send_player(pname, attrans("Please punch the signal to use as the main signal."))
+end
+
+local distant_pos = {}
+local function init_distant_assignment(pname, pos)
+ if not minetest.check_player_privs(pname, "interlocking") then
+ minetest.send_chat_player(pname, attrans("This operation is now allowed without the @1 privilege.", "interlocking"))
+ return
+ end
+ if not D.appropriate_signal(pos) then
+ minetest.chat_send_player(pname, attrans("Incompatible signal."))
+ return
+ end
+ distant_pos[pname] = pos
+ minetest.chat_send_player(pname, attrans("Please punch the signal to use as the distant signal."))
+end
+
+minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
+ local pname = player:get_player_name()
+ if not minetest.check_player_privs(pname, "interlocking") then
+ return
+ end
+ local spos = signal_pos[pname]
+ local distant = false
+ if not spos then
+ spos = distant_pos[pname]
+ if not spos then
+ return
+ end
+ distant = true
+ end
+ signal_pos[pname] = nil
+ distant_pos[pname] = nil
+ local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2
+ if not (is_signal and D.appropriate_signal(pos)) then
+ minetest.chat_send_player(pname, attrans("Incompatible signal."))
+ return
+ end
+ minetest.chat_send_player(pname, attrans("Successfully assigned signal."))
+ if distant then
+ D.assign(spos, pos, "manual")
+ else
+ D.assign(pos, spos, "manual")
+ end
+end)
+
+local dstsel = {}
+
+function advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields)
+ if not (pos and minetest.check_player_privs(pname, "interlocking")) then
+ return
+ end
+ if fields.dst_unassign then
+ D.unassign_dst(pos)
+ elseif fields.dst_assign then
+ init_signal_assignment(pname, pos)
+ elseif fields.dst_add then
+ init_distant_assignment(pname, pos)
+ elseif fields.dstlist then
+ dstsel[pname] = minetest.explode_textlist_event(fields.dstlist).index
+ elseif fields.dst_del then
+ local selid = dstsel[pname]
+ if selid then
+ local dsts = D.get_dst(pos)
+ local pos
+ for p, _ in pairs(dsts) do
+ selid = selid-1
+ if selid <= 0 then
+ pos = p
+ break
+ end
+ end
+ if pos then
+ D.unassign_dst(advtrains.decode_pos(pos))
+ end
+ end
+ end
+end
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
index cfbb8e5..4d959cc 100644
--- a/advtrains_interlocking/init.lua
+++ b/advtrains_interlocking/init.lua
@@ -1,5 +1,5 @@
--- Advtrains interlocking system
--- See database.lua for a detailed explanation
+--- Advtrains interlocking system.
+-- @module advtrains.interlocking
advtrains.interlocking = {}
@@ -12,11 +12,16 @@ end
local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELIM
+advtrains.interlocking.aspect = dofile(modpath.."aspect.lua")
+
dofile(modpath.."database.lua")
+dofile(modpath.."distant.lua")
+dofile(modpath.."distant_ui.lua")
+dofile(modpath.."signal_aspect_accessors.lua")
dofile(modpath.."signal_api.lua")
+dofile(modpath.."signal_aspect_ui.lua")
dofile(modpath.."demosignals.lua")
dofile(modpath.."train_sections.lua")
-dofile(modpath.."distant_signals.lua")
dofile(modpath.."route_prog.lua")
dofile(modpath.."routesetting.lua")
dofile(modpath.."tcb_ts_ui.lua")
diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua
index d801608..9973569 100644
--- a/advtrains_interlocking/routesetting.lua
+++ b/advtrains_interlocking/routesetting.lua
@@ -44,13 +44,18 @@ function ilrs.set_route(signal, route, try)
local i = 1
local rtename = route.name
local signalname = ildb.get_tcbs(signal).signal_name
- local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp, p_ssigd
+ local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp
+ local signals = {}
+ local nodst
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
if not try then atwarn("Did not find TCBS",c_sigd,"while setting route",rtename,"of",signal) end
return false, "No TCB found at "..sigd_to_string(c_sigd)..". Please reconfigure route!"
end
+ if i == 1 then
+ nodst = c_tcbs.nodst
+ end
c_ts_id = c_tcbs.ts_id
if not c_ts_id then
if not try then atwarn("Encountered End-Of-Interlocking while setting route",rtename,"of",signal) end
@@ -112,16 +117,9 @@ function ilrs.set_route(signal, route, try)
}
if c_tcbs.signal then
c_tcbs.route_committed = true
- local asp = route.aspect or advtrains.interlocking.GENERIC_FREE
- asp.dst = nil
- c_tcbs.aspect = asp
+ c_tcbs.aspect = route.aspect or advtrains.interlocking.FULL_FREE
c_tcbs.route_origin = signal
- advtrains.interlocking.distant.update(c_tcbs)
- -- Update the previous distant signal
- if p_ssigd then
- advtrains.interlocking.distant.assign(c_sigd, p_ssigd)
- end
- p_ssigd = c_sigd
+ signals[#signals+1] = c_tcbs
end
end
-- advance
@@ -130,15 +128,25 @@ function ilrs.set_route(signal, route, try)
i = i + 1
end
- if c_sigd and p_ssigd then
+ -- Distant signaling
+ local lastsig = nil
+ if c_sigd then
local e_tcbs = ildb.get_tcbs(c_sigd)
- if e_tcbs.signal then
- if p_stcb then
- p_stcb.aspect.dst = (e_tcbs.aspect or advtrains.interlocking.DANGER).main
- advtrains.interlocking.update_signal_aspect(p_stcb)
+ local pos = e_tcbs and e_tcbs.signal
+ if pos then
+ lastsig = pos
+ end
+ end
+ for i = #signals, 1, -1 do
+ if lastsig then
+ local tcbs = signals[i]
+ local pos = tcbs.signal
+ local _, assigned_by = advtrains.distant.get_main(pos)
+ if (not nodst) and (not assigned_by or assigned_by == "routesetting") then
+ advtrains.distant.assign(lastsig, pos, "routesetting", true)
end
+ advtrains.interlocking.update_signal_aspect(tcbs, i ~= 1)
end
- advtrains.interlocking.distant.assign(c_sigd, p_ssigd)
end
return true
@@ -247,6 +255,13 @@ function ilrs.cancel_route_from(sigd)
c_tcbs.route_auto = nil
c_tcbs.route_origin = nil
+ if c_tcbs.signal then
+ local pos = c_tcbs.signal
+ local _, assigned_by = advtrains.distant.get_main(pos)
+ if assigned_by == "routesetting" then
+ advtrains.distant.unassign_dst(pos, true)
+ end
+ end
advtrains.interlocking.update_signal_aspect(c_tcbs)
c_ts_id = c_tcbs.ts_id
@@ -326,7 +341,8 @@ function ilrs.update_route(sigd, tcbs, newrte, cancel)
end
else
--atdebug("Committed Route:",tcbs.routeset)
- has_changed_aspect = true
+ -- set_route now sets the signal aspects
+ --has_changed_aspect = true
end
end
if has_changed_aspect then
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
index a969378..ce8854a 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -1,173 +1,9 @@
-- Signal API implementation
-
---[[
-Signal aspect table:
-Note: All speeds are measured in m/s, aka the number of + signs in the HUD.
-asp = {
- main = <int speed>,
- -- Main signal aspect, tells state and permitted speed of next section
- -- 0 = section is blocked
- -- >0 = section is free, speed limit is this value
- -- -1 = section is free, maximum speed permitted
- -- false/nil = Signal doesn't provide main signal information, retain current speed limit.
- shunt = <boolean>,
- -- Whether train may proceed as shunt move, on sight
- -- main aspect takes precedence over this
- -- When main==0, train switches to shunt move and is restricted to speed 6
- proceed_as_main = <boolean>,
- -- If an approaching train is a shunt move and 'shunt' is false,
- -- the train may proceed as a train move under the "main" aspect
- -- if the main aspect permits it (i.e. main!=0)
- -- If this is not set, shunt moves are NOT allowed to switch to
- -- a train move, and must stop even if "main" would permit passing.
- -- This is intended to be used for "Halt for shunt moves" signs.
-
- dst = <int speed>,
- -- Distant signal aspect, tells state and permitted speed of the section after next section
- -- The character of these information is purely informational
- -- At this time, this field is not actively used
- -- 0 = section is blocked
- -- >0 = section is free, speed limit is this value
- -- -1 = section is free, maximum speed permitted
- -- false/nil = Signal doesn't provide distant signal information.
-
- -- the character of call_on and dead_end is purely informative
- call_on = <boolean>, -- Call-on route, expect train in track ahead (not implemented yet)
- dead_end = <boolean>, -- Route ends on a dead end (e.g. bumper) (not implemented yet)
-
- w_speed = <integer>,
- -- "Warning speed restriction". Supposed for short-term speed
- -- restrictions which always override any other restrictions
- -- imposed by "speed" fields, until lifted by a value of -1
- -- (Example: german Langsamfahrstellen-Signale)
- }
-}
-
-== How signals actually work in here ==
-Each signal (in the advtrains universe) is some node that has at least the
-following things:
-- An "influence point" that is set somewhere on a rail
-- An aspect which trains that pass the "influence point" have to obey
-
-There can be static and dynamic signals. Static signals are, roughly
-spoken, signs, while dynamic signals are "real" signals which can display
-different things.
-
-The node definition of a signal node should contain those fields:
-groups = {
- advtrains_signal = 2,
- save_in_at_nodedb = 1,
-}
-advtrains = {
- set_aspect = function(pos, node, asp)
- -- This function gets called whenever the signal should display
- -- a new or changed signal aspect. It is not required that
- -- the signal actually displays the exact same aspect, since
- -- some signals can not do this by design. However, it must
- -- display an aspect that is at least as restrictive as the passed
- -- aspect as far as it is capable of doing so.
- -- Examples:
- -- - pure shunt signals can not display a "main" aspect
- -- and have no effect on train moves, so they will only ever
- -- honor the shunt.free field for their aspect.
- -- - the german Hl system can only signal speeds of 40, 60
- -- and 100 km/h, a speed of 80km/h should then be signalled
- -- as 60 km/h instead.
- -- In turn, it is not guaranteed that the aspect will fulfill the
- -- criteria put down in supported_aspects.
- -- If set_aspect is present, supported_aspects should also be declared.
-
- -- The aspect passed in here can always be queried using the
- -- advtrains.interlocking.signal_get_supposed_aspect(pos) function.
- -- It is always DANGER when the signal is not used as route signal.
-
- -- For static signals, this function should be completely omitted
- -- If this function is omitted, it won't be possible to use
- -- route setting on this signal.
- end,
- supported_aspects = {
- -- A table which tells which different types of aspects this signal
- -- is able to display. It is used to construct the "aspect editing"
- -- formspec for route programming (and others) It should always be
- -- present alongside with set_aspect. If this is not specified but
- -- set_aspect is, the user will be allowed to select any aspect.
- -- Any of the fields marked with <boolean/nil> support 3 types of values:
- nil: if this signal can switch between free/blocked
- false: always shows "blocked", unchangable
- true: always shows "free", unchangable
- -- Any of the "speed" fields should contain a list of possible values
- -- to be set as restriction. If omitted, the value of the described
- -- field is always assumed to be false (no information)
- -- A speed of 0 means that the signal can show a "blocked" aspect
- -- (which is probably the case for most signals)
- -- If the signal can signal "no information" on one of the fields
- -- (thus false is an acceptable value), include false in the list
- -- If your signal can only display a single speed (may it be -1),
- -- always enclose that single value into a list. (such as {-1})
- main = {<speed1>, ..., <speedn>} or nil,
- dst = {<speed1>, ..., <speedn>} or nil,
- shunt = <boolean/nil>,
-
- call_on = <boolean/nil>,
- dead_end = <boolean/nil>,
- w_speed = {<speed1>, ..., <speedn>} or nil,
-
- },
- Example for supported_aspects:
- supported_aspects = {
- main = {0, 6, -1}, -- can show either "Section blocked", "Proceed at speed 6" or "Proceed at maximum speed"
- dst = {0, false}, -- can show only if next signal shows "blocked", no other information.
- shunt = false, -- shunting by this signal is never allowed.
-
- call_on = false,
- dead_end = false,
- w_speed = nil,
- -- none of the information can be shown by the signal
-
- },
-
- get_aspect = function(pos, node)
- -- This function gets called by the train safety system. It
- should return the aspect that this signal actually displays,
- not preferably the input of set_aspect.
- -- For regular, full-featured light signals, they will probably
- honor all entries in the original aspect, however, e.g.
- simple shunt signals always return main=false regardless of
- the set_aspect input because they can not signal "Halt" to
- train moves.
- -- advtrains.interlocking.DANGER contains a default "all-danger" aspect.
- -- If your signal does not cover certain sub-tables of the aspect,
- the following reasonable defaults are automatically assumed:
- main = false (unchanged)
- dst = false (unchanged)
- shunt = false (shunting not allowed)
- info = {} (no further information)
- end,
-}
-on_rightclick = advtrains.interlocking.signal_rc_handler
-can_dig = advtrains.interlocking.signal_can_dig
-after_dig_node = advtrains.interlocking.signal_after_dig
-
-(If you need to specify custom can_dig or after_dig_node callbacks,
-please call those functions anyway!)
-
-Important note: If your signal should support external ways to set its
-aspect (e.g. via mesecons), there are some things that need to be considered:
-- advtrains.interlocking.signal_get_supposed_aspect(pos) won't respect this
-- Whenever you change the signal aspect, and that aspect change
-did not happen through a call to
-advtrains.interlocking.signal_set_aspect(pos, asp), you are
-*required* to call this function:
-advtrains.interlocking.signal_on_aspect_changed(pos)
-in order to notify trains about the aspect change.
-This function will query get_aspect to retrieve the new aspect.
-
-]]--
+local F = advtrains.formspec
local DANGER = {
main = 0,
- dst = false,
shunt = false,
}
advtrains.interlocking.DANGER = DANGER
@@ -177,32 +13,18 @@ advtrains.interlocking.GENERIC_FREE = {
shunt = false,
dst = false,
}
+advtrains.interlocking.FULL_FREE = {
+ main = -1,
+ shunt = false,
+ proceed_as_main = true,
+}
-local function convert_aspect_if_necessary(asp)
- if type(asp.main) == "table" then
- local newasp = {}
- if asp.main.free then
- newasp.main = asp.main.speed
- else
- newasp.main = 0
- end
- if asp.dst and asp.dst.free then
- newasp.dst = asp.dst.speed
- else
- newasp.dst = 0
- end
- newasp.proceed_as_main = asp.shunt.proceed_as_main
- newasp.shunt = asp.shunt.free
- -- Note: info table not transferred, it's not used right now
- return newasp
- end
- return asp
-end
+advtrains.interlocking.signal_convert_aspect_if_necessary = advtrains.interlocking.aspect
-function advtrains.interlocking.update_signal_aspect(tcbs)
+function advtrains.interlocking.update_signal_aspect(tcbs, skipdst)
if tcbs.signal then
local asp = tcbs.aspect or DANGER
- advtrains.interlocking.signal_set_aspect(tcbs.signal, asp)
+ advtrains.interlocking.signal_set_aspect(tcbs.signal, asp, skipdst)
end
end
@@ -212,17 +34,9 @@ end
function advtrains.interlocking.signal_after_dig(pos)
-- clear influence point
- advtrains.interlocking.db.clear_ip_by_signalpos(pos)
-end
-function advtrains.interlocking.signal_set_aspect(pos, asp)
- asp = convert_aspect_if_necessary(asp)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
- ndef.advtrains.set_aspect(pos, node, asp)
- advtrains.interlocking.signal_on_aspect_changed(pos)
- end
+ advtrains.interlocking.signal_clear_aspect(pos)
+ advtrains.distant.unassign_all(pos, true)
end
-- should be called when aspect has changed on this signal.
@@ -230,8 +44,10 @@ function advtrains.interlocking.signal_on_aspect_changed(pos)
local ipts, iconn = advtrains.interlocking.db.get_ip_by_signalpos(pos)
if not ipts then return end
local ipos = minetest.string_to_pos(ipts)
-
- advtrains.invalidate_all_paths_ahead(ipos)
+
+ -- FIXME: invalidate_all_paths_ahead does not appear to always work as expected
+ --advtrains.invalidate_all_paths_ahead(ipos)
+ minetest.after(0, advtrains.invalidate_all_paths, ipos)
end
function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, pointed_thing)
@@ -241,7 +57,10 @@ function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack,
advtrains.interlocking.show_ip_form(pos, pname)
return
end
-
+ advtrains.interlocking.show_signal_form(pos, node, pname)
+end
+
+function advtrains.interlocking.show_signal_form(pos, node, pname)
local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos)
if sigd then
advtrains.interlocking.show_signalling_form(sigd, pname)
@@ -252,12 +71,12 @@ function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack,
local function callback(pname, aspect)
advtrains.interlocking.signal_set_aspect(pos, aspect)
end
- local isasp = ndef.advtrains.get_aspect(pos, node)
-
+ local isasp = advtrains.interlocking.signal_get_aspect(pos, node)
+
advtrains.interlocking.show_signal_aspect_selector(
pname,
ndef.advtrains.supported_aspects,
- "Set aspect manually", callback,
+ pos, callback,
isasp)
else
--static signal - only IP
@@ -278,38 +97,13 @@ function advtrains.interlocking.signal_get_supposed_aspect(pos)
return DANGER;
end
--- Returns the actual aspect of the signal at position, as returned by the nodedef.
--- returns nil when there's no signal at the position
-function advtrains.interlocking.signal_get_aspect(pos)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.get_aspect then
- local asp = ndef.advtrains.get_aspect(pos, node)
- if not asp then asp = DANGER end
- return convert_aspect_if_necessary(asp)
- end
- return nil
-end
-
--- Returns the "supported_aspects" of the signal at position, as returned by the nodedef.
--- returns nil when there's no signal at the position
-function advtrains.interlocking.signal_get_supported_aspects(pos)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.supported_aspects then
- local asp = ndef.advtrains.supported_aspects
- return asp
- end
- return nil
-end
-
local players_assign_ip = {}
local function ipmarker(ipos, connid)
local node_ok, conns, rhe = advtrains.get_rail_info_at(ipos, advtrains.all_tracktypes)
if not node_ok then return end
local yaw = advtrains.dir_to_angle(conns[connid].c)
-
+
-- using tcbmarker here
local obj = minetest.add_entity(vector.add(ipos, {x=0, y=0.2, z=0}), "advtrains_interlocking:tcbmarker")
if not obj then return end
@@ -319,48 +113,72 @@ local function ipmarker(ipos, connid)
})
end
--- shows small info form for signal IP state/assignment
+function advtrains.interlocking.make_ip_formspec_component(pos, x, y, w)
+ advtrains.interlocking.db.check_for_duplicate_ip(pos)
+ local pts, connid = advtrains.interlocking.db.get_ip_by_signalpos(pos)
+ if pts then
+ return table.concat {
+ F.S_label(x, y, "Influence point is set at @1.", string.format("%s/%s", pts, connid)),
+ F.S_button_exit(x, y+0.5, w/2-0.125, "ip_set", "Modify"),
+ F.S_button_exit(x+w/2+0.125, y+0.5, w/2-0.125, "ip_clear", "Clear"),
+ }, pts, connid
+ else
+ return table.concat {
+ F.S_label(x, y, "Influence point is not set."),
+ F.S_button_exit(x, y+0.5, w, "ip_set", "Set influence point"),
+ }
+ end
+end
+
+-- shows small info form for signal properties
+-- This function is named show_ip_form because it was originally only intended
+-- for assigning/changing the influence point.
-- only_notset: show only if it is not set yet (used by signal tcb assignment)
function advtrains.interlocking.show_ip_form(pos, pname, only_notset)
if not minetest.check_player_privs(pname, "interlocking") then
return
end
- local form = "size[7,5]label[0.5,0.5;Signal at "..minetest.pos_to_string(pos).."]"
- local pts, connid = advtrains.interlocking.db.get_ip_by_signalpos(pos)
+ local ipform, pts, connid = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 0.5, 7)
+ local form = {
+ "formspec_version[4]",
+ "size[8,2.25]",
+ ipform,
+ }
if pts then
- form = form.."label[0.5,1.5;Influence point is set at "..pts.."/"..connid.."]"
- form = form.."button_exit[0.5,2.5; 5,1;set;Move]"
- form = form.."button_exit[0.5,3.5; 5,1;clear;Clear]"
local ipos = minetest.string_to_pos(pts)
ipmarker(ipos, connid)
- else
- form = form.."label[0.5,1.5;Influence point is not set.]"
- form = form.."label[0.5,2.0;It is recommended to set an influence point.]"
- form = form.."label[0.5,2.5;This is the point where trains will obey the signal.]"
-
- form = form.."button_exit[0.5,3.5; 5,1;set;Set]"
end
+ if advtrains.distant.appropriate_signal(pos) then
+ form[#form+1] = advtrains.interlocking.make_dst_formspec_component(pos, 0.5, 2, 7, 4.25)
+ form[2] = "size[8,6.75]"
+ end
+ form = table.concat(form)
if not only_notset or not pts then
- minetest.show_formspec(pname, "at_il_ipassign_"..minetest.pos_to_string(pos), form)
+ minetest.show_formspec(pname, "at_il_propassign_"..minetest.pos_to_string(pos), form)
end
end
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then
+function advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields)
+ if not (pos and minetest.check_player_privs(pname, {train_operator=true, interlocking=true})) then
return
end
- local pts = string.match(formname, "^at_il_ipassign_([^_]+)$")
+ if fields.ip_set then
+ advtrains.interlocking.signal_init_ip_assign(pos, pname)
+ elseif fields.ip_clear then
+ advtrains.interlocking.db.clear_ip_by_signalpos(pos)
+ end
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ local pname = player:get_player_name()
+ local pts = string.match(formname, "^at_il_propassign_([^_]+)$")
local pos
if pts then
pos = minetest.string_to_pos(pts)
end
if pos then
- if fields.set then
- advtrains.interlocking.signal_init_ip_assign(pos, pname)
- elseif fields.clear then
- advtrains.interlocking.db.clear_ip_by_signalpos(pos)
- end
+ advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields)
+ advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields)
end
end)
@@ -410,129 +228,3 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
players_assign_ip[pname] = nil
end
end)
-
-
---== aspect selector ==--
-
-local players_aspsel = {}
-
---[[
-suppasp: "supported_aspects" table
-purpose: form title string
-callback: func(pname, aspect) called on form submit
-isasp: aspect currently set
-]]
-function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_purpose, callback, isasp)
- local suppasp = p_suppasp or {
- main = {0, -1}, dst = {false}, shunt = false, info = {},
- }
- local purpose = p_purpose or ""
-
- local form = "size[7,7]label[0.5,0.5;Select Signal Aspect:]"
- form = form.."label[0.5,1;"..purpose.."]"
-
- form = form.."label[0.5,1.5;== Main Signal ==]"
- local selid = 1
- local entries = {}
- for idx, spv in ipairs(suppasp.main) do
- local entry
- if spv == 0 then
- entry = "Halt"
- elseif spv == -1 then
- entry = "Continue at maximum speed"
- elseif not spv then
- entry = "Continue\\, speed limit unchanged (no info)"
- else
- entry = "Continue at speed of "..spv
- end
- -- hack: the crappy formspec system returns the label, not the index. save the index in it.
- entries[idx] = idx.."| "..entry
- if isasp and spv == (isasp.main or false) then
- selid = idx
- end
- end
- form = form.."dropdown[0.5,2;6;main;"..table.concat(entries, ",")..";"..selid.."]"
-
-
- form = form.."label[0.5,3;== Shunting ==]"
- if suppasp.shunt == nil then
- local st = 1
- if isasp and isasp.shunt then st=2 end
- form = form.."dropdown[0.5,3.5;6;shunt_free;---,allowed;"..st.."]"
- end
-
- form = form.."label[0.5,4.5;== Distant Signal ==]"
- local selid = 1
- local entries = {}
- for idx, spv in ipairs(suppasp.dst) do
- local entry
- if spv == 0 then
- entry = "Expect to stop at the next signal"
- elseif spv == -1 then
- entry = "Expect to pass the next signal at maximum speed"
- elseif not spv then
- entry = "No info"
- else
- entry = string.format("Expect to pass the next signal at speed of %d", spv)
- end
- entries[idx] = idx.."| "..entry
- if isasp and spv == (isasp.dst or false) then
- selid = idx
- end
- end
- form = form.."dropdown[0.5,5;6;dst;"..table.concat(entries, ",")..";"..selid.."]"
-
- form = form.."button_exit[0.5,6;5,1;save;Save signal aspect]"
-
- local token = advtrains.random_id()
-
- minetest.show_formspec(pname, "at_il_sigaspdia_"..token, form)
-
- minetest.after(1, function()
- players_aspsel[pname] = {
- suppasp = suppasp,
- callback = callback,
- token = token,
- }
- end)
-end
-
-local function usebool(sup, val, free)
- if sup == nil then
- return val==free
- else
- return sup
- end
-end
-
--- other side of hack: extract the index
-local function ddindex(val)
- return tonumber(string.match(val, "^(%d+)|"))
-end
-
--- TODO use non-hacky way to parse outputs
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- local pname = player:get_player_name()
- local psl = players_aspsel[pname]
- if psl then
- if formname == "at_il_sigaspdia_"..psl.token then
- if fields.save then
- local maini = ddindex(fields.main)
- if not maini then return end
- local dsti = ddindex(fields.dst)
- if not dsti then return end
- local asp = {
- main = psl.suppasp.main[maini],
- dst = psl.suppasp.dst[dsti],
- shunt = usebool(psl.suppasp.shunt, fields.shunt_free, "allowed"),
- info = {}
- }
- psl.callback(pname, asp)
- end
- else
- players_aspsel[pname] = nil
- end
- end
-
-end)
diff --git a/advtrains_interlocking/signal_aspect_accessors.lua b/advtrains_interlocking/signal_aspect_accessors.lua
new file mode 100644
index 0000000..d91df31
--- /dev/null
+++ b/advtrains_interlocking/signal_aspect_accessors.lua
@@ -0,0 +1,163 @@
+--- Signal aspect accessors
+-- @module advtrains.interlocking
+
+local A = advtrains.interlocking.aspect
+local D = advtrains.distant
+local I = advtrains.interlocking
+local N = advtrains.ndb
+local pts = advtrains.roundfloorpts
+
+local get_aspect
+
+local supposed_aspects = {}
+
+--- Replace the signal aspect cache.
+-- @function load_supposed_aspects
+-- @param db The new database.
+function I.load_supposed_aspects(tbl)
+ if tbl then
+ supposed_aspects = {}
+ for k, v in pairs(tbl) do
+ supposed_aspects[k] = A(v)
+ end
+ end
+end
+
+--- Retrieve the signal aspect cache.
+-- @function save_supposed_aspects
+-- @return The current database in use.
+function I.save_supposed_aspects()
+ local t = {}
+ for k, v in pairs(supposed_aspects) do
+ t[k] = v:plain(true)
+ end
+ return t
+end
+
+--- Read the aspect of a signal strictly from cache.
+-- @param pos The position of the signal.
+-- @return[1] The aspect of the signal (if present in cache).
+-- @return[2] The nil constant (otherwise).
+local function get_supposed_aspect(pos)
+ return supposed_aspects[pts(pos)]
+end
+
+--- Update the signal aspect information in cache.
+-- @param pos The position of the signal.
+-- @param asp The new signal aspect
+local function set_supposed_aspect(pos, asp)
+ supposed_aspects[pts(pos)] = asp
+end
+
+--- Get the definition of a node.
+-- @param pos The position of the node.
+-- @return[1] The definition of the node (if present).
+-- @return[2] An empty table (otherwise).
+local function get_ndef(pos)
+ local node = N.get_node(pos)
+ return (minetest.registered_nodes[node.name] or {}), node
+end
+
+--- Get the aspects supported by a signal.
+-- @function signal_get_supported_aspects
+-- @param pos The position of the signal.
+-- @return[1] The table of supported aspects (if present).
+-- @return[2] The nil constant (otherwise).
+local function get_supported_aspects(pos)
+ local ndef = get_ndef(pos)
+ if ndef.advtrains and ndef.advtrains.supported_aspects then
+ return ndef.advtrains.supported_aspects
+ end
+ return nil
+end
+
+--- Adjust a new signal aspect to fit a signal.
+-- @param pos The position of the signal.
+-- @param asp The new signal aspect.
+-- @return The adjusted signal aspect.
+-- @return The information to pass to the `advtrains.set_aspect` field in the node definitions.
+local function adjust_aspect(pos, asp)
+ local asp = A(asp)
+
+ local mainpos = D.get_main(pos)
+ local nxtasp
+ if mainpos then
+ nxtasp = get_aspect(mainpos)
+ end
+ local suppasp = get_supported_aspects(pos)
+ if not suppasp then
+ return asp
+ end
+ return asp:adjust_distant(nxtasp, suppasp.dst_shift):to_group(suppasp.group)
+end
+
+--- Get the aspect of a signal without accessing the cache.
+-- For most cases, `get_aspect` should be used instead.
+-- @function signal_get_real_aspect
+-- @param pos The position of the signal.
+-- @return[1] The signal aspect adjusted using `adjust_aspect` (if present).
+-- @return[2] The nil constant (otherwise).
+local function get_real_aspect(pos)
+ local ndef, node = get_ndef(pos)
+ if ndef.advtrains and ndef.advtrains.get_aspect then
+ local asp = ndef.advtrains.get_aspect(pos, node) or I.DANGER
+ return adjust_aspect(pos, asp)
+ end
+ return nil
+end
+
+--- Get the aspect of a signal.
+-- @function signal_get_aspect
+-- @param pos The position of the signal.
+-- @return[1] The aspect of the signal (if present).
+-- @return[2] The nil constant (otherwise).
+get_aspect = function(pos)
+ local asp = get_supposed_aspect(pos)
+ if not asp then
+ asp = get_real_aspect(pos)
+ set_supposed_aspect(pos, asp)
+ end
+ return asp
+end
+
+--- Set the aspect of a signal.
+-- @function signal_set_aspect
+-- @param pos The position of the signal.
+-- @param asp The new signal aspect.
+-- @param[opt=false] skipdst Whether to skip updating distant signals.
+local function set_aspect(pos, asp, skipdst)
+ local node = N.get_node(pos)
+ local ndef = minetest.registered_nodes[node.name]
+ if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
+ local oldasp = I.signal_get_aspect(pos) or DANGER
+ local newasp = adjust_aspect(pos, asp)
+ set_supposed_aspect(pos, newasp)
+ ndef.advtrains.set_aspect(pos, node, newasp)
+ I.signal_on_aspect_changed(pos)
+ local aspect_changed = oldasp ~= newasp
+ if (not skipdst) and aspect_changed then
+ D.update_main(pos)
+ end
+ end
+end
+
+--- Remove a signal from cache.
+-- @function signal_clear_aspect
+-- @param pos The position of the signal.
+local function clear_aspect(pos)
+ set_supposed_aspect(pos, nil)
+end
+
+--- Readjust the aspect of a signal.
+-- @function signal_readjust_aspect
+-- @param pos The position of the signal.
+local function readjust_aspect(pos)
+ set_aspect(pos, get_aspect(pos))
+end
+
+I.signal_get_supported_aspects = get_supported_aspects
+I.signal_get_real_aspect = get_real_aspect
+I.signal_get_aspect = get_aspect
+I.signal_set_aspect = set_aspect
+I.signal_clear_aspect = clear_aspect
+I.signal_readjust_aspect = readjust_aspect
diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua
new file mode 100644
index 0000000..a81b7fe
--- /dev/null
+++ b/advtrains_interlocking/signal_aspect_ui.lua
@@ -0,0 +1,262 @@
+local F = advtrains.formspec
+local players_aspsel = {}
+
+local function describe_main_aspect(spv)
+ if spv == 0 then
+ return attrans("Danger (halt)")
+ elseif spv == -1 then
+ return attrans("Continue at maximum speed")
+ elseif not spv then
+ return attrans("Continue with current speed limit")
+ else
+ return attrans("Continue with the speed limit of @1", tostring(spv))
+ end
+end
+
+local function describe_shunt_aspect(shunt)
+ if shunt then
+ return attrans("Shunting allowed")
+ else
+ return attrans("No shunting")
+ end
+end
+
+local function describe_distant_aspect(spv)
+ if spv == 0 then
+ return attrans("Expect to stop at the next signal")
+ elseif spv == -1 then
+ return attrans("Expect to continue at maximum speed")
+ elseif not spv then
+ return attrans("No distant signal information")
+ else
+ return attrans("Expect to continue with a speed limit of @1", tostring(spv))
+ end
+end
+
+advtrains.interlocking.describe_main_aspect = describe_main_aspect
+advtrains.interlocking.describe_shunt_aspect = describe_shunt_aspect
+advtrains.interlocking.describe_distant_aspect = describe_distant_aspect
+
+local function dsel(p, q, x, y)
+ if p == nil then
+ if q then
+ return x
+ else
+ return y
+ end
+ elseif p then
+ return x
+ else
+ return y
+ end
+end
+
+local function describe_supported_aspects(suppasp, isasp)
+ local t = {}
+
+ local entries = {attrans("Use default value")}
+ local selid = 0
+ local mainasps = suppasp.main
+ if type(mainasps) ~= "table" then
+ mainasps = {mainasps}
+ end
+ for idx, spv in ipairs(mainasps) do
+ if isasp and spv == rawget(isasp, "main") then
+ selid = idx
+ end
+ entries[idx+1] = describe_main_aspect(spv)
+ end
+ t.main = entries
+ t.main_current = selid+1
+ t.main_string = tostring(isasp.main)
+ if t.main == nil then
+ t.main_string = ""
+ end
+
+ t.shunt = {
+ attrans("No shunting"),
+ attrans("Shunting allowed"),
+ attrans("Proceed as main"),
+ }
+
+ t.shunt_current = dsel(suppasp.shunt, isasp.shunt, 2, 1)
+ if dsel(suppasp.proceed_as_main, isasp.proceed_as_main, t.shunt_current == 1) then
+ t.shunt_current = 3
+ end
+ t.shunt_const = suppasp.shunt ~= nil
+
+ if suppasp.group then
+ local gdef = advtrains.interlocking.aspect.get_group_definition(suppasp.group)
+ if gdef then
+ t.group = suppasp.group
+ t.groupdef = gdef
+ local entries = {}
+ local selid = 1
+ for idx, name in ipairs(suppasp.name or {}) do
+ entries[idx] = gdef.aspects[name].label
+ if suppasp.group == isasp.group and name == isasp.name then
+ selid = idx
+ end
+ end
+ t.name = entries
+ t.name_current = selid
+ end
+ end
+
+ return t
+end
+
+advtrains.interlocking.describe_supported_aspects = describe_supported_aspects
+
+local function make_signal_aspect_selector(suppasp, purpose, isasp)
+ local t = describe_supported_aspects(suppasp, isasp)
+ local formmode = 1
+
+ local pos
+ if type(purpose) == "table" then
+ formmode = 2
+ pos = purpose.pos
+ end
+
+ local form = {
+ "formspec_version[4]",
+ string.format("size[8,%f]", ({5.75, 10.75})[formmode]),
+ F.S_label(0.5, 0.5, "Select signal aspect"),
+ }
+ local h0 = ({0, 1.5})[formmode]
+ form[#form+1] = F.S_label(0.5, 1.5+h0, "Main aspect")
+ form[#form+1] = F.S_label(0.5, 3+h0, "Shunt aspect")
+ form[#form+1] = F.S_button_exit(0.5, 4.5+h0, 7, "asp_save", "Save signal aspect")
+ if formmode == 1 then
+ form[#form+1] = F.label(0.5, 1, purpose)
+ form[#form+1] = F.field(0.5, 2, 7, "asp_mainval", "", t.main_string)
+ elseif formmode == 2 then
+ if t.group then
+ form[#form+1] = F.S_label(0.5, 1.5, "Signal aspect group: @1", t.groupdef.label)
+ form[#form+1] = F.dropdown(0.5, 2, 7, "asp_namesel", t.name, t.name_current, true)
+ else
+ form[#form+1] = F.S_label(0.5, 1.5, "This signal does not belong to a signal aspect group.")
+ form[#form+1] = F.S_label(0.5, 2, "You can not use a predefined signal aspect.")
+ end
+ form[#form+1] = F.S_label(0.5, 1, "Signal at @1", minetest.pos_to_string(pos))
+ form[#form+1] = F.dropdown(0.5, 3.5, 7, "asp_mainsel", t.main, t.main_current, true)
+ form[#form+1] = advtrains.interlocking.make_ip_formspec_component(pos, 0.5, 7, 7)
+ form[#form+1] = advtrains.interlocking.make_short_dst_formspec_component(pos, 0.5, 8.5, 7)
+ end
+
+ if formmode == 2 and t.shunt_const then
+ form[#form+1] = F.label(0.5, 3.5+h0, t.shunt[t.shunt_current])
+ form[#form+1] = F.S_label(0.5, 4+h0, "The shunt aspect cannot be changed.")
+ else
+ form[#form+1] = F.dropdown(0.5, 3.5+h0, 7, "asp_shunt", t.shunt, t.shunt_current, true)
+ end
+
+ return table.concat(form)
+end
+
+function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_purpose, callback, isasp)
+ local suppasp = p_suppasp or {
+ main = {0, -1},
+ dst = {false},
+ shunt = false,
+ info = {},
+ }
+ local purpose = p_purpose or ""
+ local pos
+ if type(p_purpose) == "table" then
+ pos = p_purpose
+ purpose = {pname = pname, pos = pos}
+ end
+
+ local form = make_signal_aspect_selector(suppasp, purpose, isasp)
+ if not form then
+ return
+ end
+
+ local token = advtrains.random_id()
+ minetest.show_formspec(pname, "at_il_sigaspdia_"..token, form)
+ minetest.after(0, function()
+ players_aspsel[pname] = {
+ purpose = purpose,
+ suppasp = suppasp,
+ callback = callback,
+ token = token,
+ }
+ end)
+end
+
+local function usebool(sup, val, free)
+ if sup == nil then
+ return val == free
+ else
+ return sup
+ end
+end
+
+local function get_aspect_from_formspec(suppasp, fields, psl)
+ local namei, group, name = tonumber(fields.asp_namesel), suppasp.group, nil
+ local gdef = advtrains.interlocking.aspect.get_group_definition(group)
+ if gdef then
+ local names = suppasp.name or {}
+ name = names[namei] or names[names]
+ else
+ group = nil
+ end
+ local maini = tonumber(fields.asp_mainsel)
+ local main = (suppasp.main or {})[(maini or 0)-1]
+ if not maini then
+ local mainval = fields.asp_mainval
+ if mainval == "-1" then
+ main = -1
+ elseif mainval == "x" then
+ main = false
+ elseif string.match(mainval, "^%d+$") then
+ main = tonumber(mainval)
+ else
+ main = nil
+ end
+ elseif maini <= 1 then
+ main = nil
+ end
+ local shunti = tonumber(fields.asp_shunt)
+ local shunt = suppasp.shunt
+ if shunt == nil then
+ shunt = shunti == 2
+ end
+ local proceed_as_main = suppasp.proceed_as_main
+ if proceed_as_main == nil then
+ proceed_as_main = shunti == 3
+ end
+ return advtrains.interlocking.aspect {
+ main = main,
+ shunt = shunt,
+ proceed_as_main = proceed_as_main,
+ info = {},
+ name = name,
+ group = group,
+ }
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ local pname = player:get_player_name()
+ local psl = players_aspsel[pname]
+ if psl then
+ if formname == "at_il_sigaspdia_"..psl.token then
+ local suppasp = psl.suppasp
+ if fields.asp_save then
+ local asp
+ asp = get_aspect_from_formspec(suppasp, fields, psl)
+ if asp then
+ psl.callback(pname, asp)
+ end
+ end
+ if type(psl.purpose) == "table" then
+ local pos = psl.purpose.pos
+ advtrains.interlocking.handle_ip_formspec_fields(pname, pos, fields)
+ advtrains.interlocking.handle_dst_formspec_fields(pname, pos, fields)
+ end
+ else
+ players_aspsel[pname] = nil
+ end
+ end
+end)
diff --git a/advtrains_interlocking/spec/ars_spec.lua b/advtrains_interlocking/spec/ars_spec.lua
new file mode 100644
index 0000000..085dbcb
--- /dev/null
+++ b/advtrains_interlocking/spec/ars_spec.lua
@@ -0,0 +1,67 @@
+-- test the serialization function
+
+
+package.path = "../?.lua;" .. package.path
+
+
+
+
+_G.advtrains = {}
+_G.advtrains.interlocking = {}
+
+require("ars")
+
+local arstb = {{ ln="Foo"}, {c="Bar"}, {n=true, rc="Boo"}}
+local arsdef = {{ ln="Foo"}, {c="Bar"}, {rc="Boo"}, default=true}
+local arstr = [[LN Foo
+#Bar
+!RC Boo]]
+local defstr = [[*
+LN Foo
+#Bar
+RC Boo]]
+il = _G.advtrains.interlocking
+
+describe("ars_to_text", function ()
+ it("read table", function ()
+ assert.equals(il.ars_to_text(arstb),arstr)
+ end)
+ it("reads back and forth", function ()
+ assert.equals(il.ars_to_text(il.text_to_ars(arstr)),arstr)
+ end)
+ it("handles default routes properly", function ()
+ assert.equals(il.ars_to_text(arsdef),defstr)
+ end)
+end)
+
+describe("text_to_ars", function ()
+ it("writes table", function()
+ assert.same(il.text_to_ars(arstr),arstb)
+ end)
+ it("handles default routes properly", function ()
+ assert.same(il.text_to_ars(defstr),arsdef)
+ end)
+end)
+
+train1 = {}
+train2 = {}
+train3 = {}
+train1.line = "Foo"
+train1.routingcode = "Boo"
+train2.line= "Bar"
+train2.routingcode = "NotBoo NotBoo"
+train3.routingcode = "Foo Boo Moo Zoo"
+
+describe("check_rule_match", function ()
+ it("matches rules correctly", function()
+ assert.equals(il.ars_check_rule_match(arstb,train1),1)
+ assert.equals(il.ars_check_rule_match(arsdef,train2),nil)
+ end)
+ it("matches negative rules", function()
+ assert.equals(il.ars_check_rule_match(arstb,train2),3)
+ assert.equals(il.ars_check_rule_match(arstb,train3),nil)
+ end)
+ it("matches RC in a list correctly", function()
+ assert.equals(il.ars_check_rule_match(arsdef,train3),3)
+ end)
+end)
diff --git a/advtrains_interlocking/spec/basic_signalling_spec.lua b/advtrains_interlocking/spec/basic_signalling_spec.lua
new file mode 100644
index 0000000..a4e1e3a
--- /dev/null
+++ b/advtrains_interlocking/spec/basic_signalling_spec.lua
@@ -0,0 +1,106 @@
+--[[
+This file tests a large part of the signaling system, as a lot of tests for the
+signaling system tend to overlap for various parts of the system.
+]]
+
+require("mineunit")
+mineunit("core")
+
+_G.advtrains = {
+ interlocking = {
+ aspect = fixture("../../aspect"),
+ },
+ ndb = {
+ get_node = minetest.get_node,
+ swap_node = minetest.swap_node,
+ }
+}
+
+fixture("advtrains_helpers")
+fixture("../../database")
+sourcefile("distant")
+sourcefile("signal_api")
+sourcefile("signal_aspect_accessors")
+fixture("../../demosignals")
+
+minetest.register_node("advtrains_interlocking:signal_sign", {
+ advtrains = {
+ get_aspcet = function() return {main = 19} end
+ }
+})
+
+local D = advtrains.distant
+local I = advtrains.interlocking
+local A = I.aspect
+
+local stub_aspect_t1 = {
+ free = {main = -1},
+ slow = {main = 6},
+ danger = {main = 0, shunt = false},
+}
+for k, v in pairs(stub_aspect_t1) do
+ stub_aspect_t1[k] = A(v)
+end
+local stub_pos_t1 = {}
+for i = 1, 4 do
+ stub_pos_t1[i] = {x = 1, y = 0, z = i}
+end
+
+world.layout {
+ {stub_pos_t1[1], "advtrains_interlocking:ds_danger"},
+ {stub_pos_t1[2], "advtrains_interlocking:ds_slow"},
+ {stub_pos_t1[3], "advtrains_interlocking:ds_free"},
+ {stub_pos_t1[4], "advtrains_interlocking:signal_sign"},
+}
+
+describe("API for supposed signal aspects", function()
+ it("should load and save data properly", function()
+ local tbl = {_foo = {}}
+ I.load_supposed_aspects(tbl)
+ assert.same(tbl, I.save_supposed_aspects())
+ end)
+ it("should set and get signals properly", function ()
+ local pos = stub_pos_t1[2]
+ local asp = stub_aspect_t1.slow
+ local newasp = A{ main = math.random(1,5) }
+ assert.equal(asp, I.signal_get_aspect(pos))
+ I.signal_set_aspect(pos, newasp)
+ assert.equal(newasp, I.signal_get_aspect(pos))
+ assert.equal(asp, I.signal_get_real_aspect(pos))
+ I.signal_set_aspect(pos, asp)
+ end)
+end)
+
+describe("Distant signaling", function()
+ it("should assign distant signals and set the distant aspect correspondingly", function()
+ for i = 1, 2 do
+ D.assign(stub_pos_t1[i], stub_pos_t1[i+1])
+ end
+ assert.equal(stub_aspect_t1.danger, I.signal_get_aspect(stub_pos_t1[1]))
+ assert.equal(A{main = 6, dst = 0}, I.signal_get_aspect(stub_pos_t1[2]))
+ assert.equal(A{main = -1, dst = 6}, I.signal_get_aspect(stub_pos_t1[3]))
+ end)
+ it("should report assignments properly", function()
+ assert.same({stub_pos_t1[1], "manual"}, {D.get_main(stub_pos_t1[2])})
+ assert.same({[advtrains.encode_pos(stub_pos_t1[3])] = "manual"}, D.get_dst(stub_pos_t1[2]))
+ end)
+ it("should update distant aspects automatically", function()
+ I.signal_set_aspect(stub_pos_t1[2], {main = 2, dst = -1})
+ assert.equal(A{main = 2, dst = 0}, I.signal_get_aspect(stub_pos_t1[2]))
+ assert.equal(A{main = -1, dst = 2}, I.signal_get_aspect(stub_pos_t1[3]))
+ end)
+ it("should unassign signals when one is removed", function()
+ world.set_node(stub_pos_t1[2], "air")
+ assert.same({}, D.get_dst(stub_pos_t1[1]))
+ assert.same({}, {D.get_main(stub_pos_t1[3])})
+ assert.same(stub_aspect_t1.free, I.signal_get_aspect(stub_pos_t1[3]))
+ end)
+ it("should reject signal signs", function()
+ D.assign(stub_pos_t1[1], stub_pos_t1[4])
+ assert.same({}, D.get_dst(stub_pos_t1[1]))
+ assert.same({}, {D.get_main(stub_pos_t1[4])})
+ D.assign(stub_pos_t1[4], stub_pos_t1[1])
+ assert.same({}, D.get_dst(stub_pos_t1[4]))
+ assert.same({}, {D.get_main(stub_pos_t1[1])})
+ end)
+end)
diff --git a/advtrains_interlocking/spec/fixtures/advtrains_helpers.lua b/advtrains_interlocking/spec/fixtures/advtrains_helpers.lua
new file mode 120000
index 0000000..9b0ab67
--- /dev/null
+++ b/advtrains_interlocking/spec/fixtures/advtrains_helpers.lua
@@ -0,0 +1 @@
+../../../advtrains/helpers.lua \ No newline at end of file
diff --git a/advtrains_interlocking/spec/mineunit.conf b/advtrains_interlocking/spec/mineunit.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/advtrains_interlocking/spec/mineunit.conf
diff --git a/advtrains_interlocking/spec/signal_group_spec.lua b/advtrains_interlocking/spec/signal_group_spec.lua
new file mode 100644
index 0000000..bc9d007
--- /dev/null
+++ b/advtrains_interlocking/spec/signal_group_spec.lua
@@ -0,0 +1,95 @@
+require "mineunit"
+mineunit("core")
+
+_G.advtrains = {
+ interlocking = {
+ aspect = sourcefile("aspect"),
+ },
+ ndb = {
+ get_node = minetest.get_node,
+ swap_node = minetest.swap_node,
+ }
+}
+
+fixture("advtrains_helpers")
+sourcefile("database")
+sourcefile("signal_api")
+sourcefile("distant")
+sourcefile("signal_aspect_accessors")
+
+local A = advtrains.interlocking.aspect
+local D = advtrains.distant
+local I = advtrains.interlocking
+local N = advtrains.ndb
+
+local groupdef = {
+ name = "foo",
+ aspects = {
+ proceed = {main = -1},
+ caution = {},
+ danger = {main = 0},
+ "proceed",
+ {"caution"},
+ "danger",
+ },
+}
+
+for k, v in pairs(groupdef.aspects) do
+ minetest.register_node("advtrains_interlocking:" .. k, {
+ advtrains = {
+ supported_aspects = {
+ group = "foo",
+ },
+ get_aspect = function() return A{group = "foo", name = k} end,
+ set_aspect = function(pos, _, name)
+ N.swap_node(pos, {name = "advtrains_interlocking:" .. name})
+ end,
+ }
+ })
+end
+
+local origin = vector.new(0, 0, 0)
+local dstpos = vector.new(0, 0, 1)
+
+world.layout {
+ {origin, "advtrains_interlocking:danger"},
+ {dstpos, "advtrains_interlocking:proceed"},
+}
+
+describe("signal group registration", function()
+ it("should work", function()
+ A.register_group(groupdef)
+ assert(A.get_group_definition("foo"))
+ end)
+ it("should only be allowed once for the same group", function()
+ assert.has.errors(function() A.register_group(type2def) end)
+ end)
+ it("should handle nonexistant groups", function()
+ assert.is_nil(A.get_group_definition("something_else"))
+ end)
+ it("should reject invalid definitions", function()
+ assert.has.errors(function() A.register_group({}) end)
+ assert.has.errors(function() A.register_group({name="",label={}}) end)
+ assert.has.errors(function() A.register_group({name="",aspects={}}) end)
+ end)
+end)
+
+describe("signal aspect", function()
+ it("should handle empty fields properly", function()
+ assert.equal(A{main = 0}, A{group="foo", name="danger"}:to_group())
+ end)
+ it("should be converted properly", function()
+ assert.equal(A{main = 0}, A{group="foo", name="danger"})
+ assert.equal(A{}, A{group="foo", name="caution"})
+ assert.equal(A{main = -1}, A{group="foo", name="proceed"})
+ end)
+end)
+
+describe("signals in groups", function()
+ it("should support distant signaling", function()
+ assert.equal("caution", A():adjust_distant(A{group="foo",name="danger"}).name)
+ assert.equal("proceed", A():adjust_distant(A{group="foo",name="caution"}).name)
+ assert.equal("proceed", A():adjust_distant(A{group="foo",name="proceed"}).name)
+ assert.equal("danger", A{group="foo",name="danger"}:adjust_distant{}.name)
+ end)
+end)
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index 2425bf2..9aea18c 100755
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -14,6 +14,7 @@ local lntrans = { "A", "B" }
local function sigd_to_string(sigd)
return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
end
+advtrains.interlocking.sigd_to_string = sigd_to_string
minetest.register_node("advtrains_interlocking:tcb_node", {
drawtype = "mesh",
@@ -197,20 +198,24 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
if is_signal then
local ndef = minetest.registered_nodes[node.name]
if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
- local tcbs = ildb.get_tcbs(sigd)
- if tcbs then
- tcbs.signal = pos
- if not tcbs.signal_name then
- tcbs.signal_name = "Signal at "..minetest.pos_to_string(sigd.p)
+ if ndef.advtrains.supported_aspects and not ndef.advtrains.supported_aspects.dst_shift then
+ local tcbs = ildb.get_tcbs(sigd)
+ if tcbs then
+ tcbs.signal = pos
+ if not tcbs.signal_name then
+ tcbs.signal_name = "Signal at "..minetest.pos_to_string(sigd.p)
+ end
+ if not tcbs.routes then
+ tcbs.routes = {}
+ end
+ ildb.set_sigd_for_signal(pos, sigd)
+ minetest.chat_send_player(pname, "Configuring TCB: Successfully assigned signal.")
+ advtrains.interlocking.show_ip_form(pos, pname, true)
+ else
+ minetest.chat_send_player(pname, "Configuring TCB: Internal error, TCBS doesn't exist. Aborted.")
end
- if not tcbs.routes then
- tcbs.routes = {}
- end
- ildb.set_sigd_for_signal(pos, sigd)
- minetest.chat_send_player(pname, "Configuring TCB: Successfully assigned signal.")
- advtrains.interlocking.show_ip_form(pos, pname, true)
else
- minetest.chat_send_player(pname, "Configuring TCB: Internal error, TCBS doesn't exist. Aborted.")
+ minetest.chat_send_player(pname, "Configuring TCB: Cannot use distant signal. Aborted.")
end
else
minetest.chat_send_player(pname, "Configuring TCB: Cannot use static signals for routesetting. Aborted.")
@@ -608,7 +613,7 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
if not tcbs.signal_name then tcbs.signal_name = "Signal at "..minetest.pos_to_string(sigd.p) end
if not tcbs.routes then tcbs.routes = {} end
- local form = "size[7,10]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]"
+ local form = "size[7,10.25]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]"
form = form.."field[0.8,1.5;5.2,1;name;Signal name;"..minetest.formspec_escape(tcbs.signal_name).."]"
form = form.."button[5.5,1.2;1,1;setname;Set]"
@@ -668,12 +673,8 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
if hasprivs then
form = form.."button[0.5,8;2.5,1;newroute;New Route]"
form = form.."button[ 3,8;2.5,1;unassign;Unassign Signal]"
- form = form.."button[ 3,9;2.5,1;influp;Influence Point]"
- end
- if tcbs.ars_disabled then
- form = form.."button[0.5,9;2.5,1;arsenable;Enable ARS]"
- else
- form = form.."button[0.5,9;2.5,1;arsdisable;Disable ARS]"
+ form = form..string.format("checkbox[0.5,8.75;ars;Automatic routesetting;%s]", not tcbs.ars_disabled)
+ form = form..string.format("checkbox[0.5,9.25;dst;Distant signalling;%s]", not tcbs.nodst)
end
elseif sigd_equal(tcbs.route_origin, sigd) then
-- something has gone wrong: tcbs.routeset should have been set...
@@ -723,11 +724,17 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
connid = tonumber(connids)
if not connid or connid<1 or connid>2 then return end
end
- if pos and connid and not fields.quit then
+ if pos and connid then
local sigd = {p=pos, s=connid}
local tcbs = ildb.get_tcbs(sigd)
if not tcbs then return end
-
+
+ if fields.quit then
+ -- form quit: disable temporary ARS ignore
+ tcbs.ars_ignore_next = nil
+ return
+ end
+
local sel_rte
if fields.rtelist then
local tev = minetest.explode_textlist_event(fields.rtelist)
@@ -740,7 +747,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
if tcbs.routeset and fields.cancelroute then
if tcbs.routes[tcbs.routeset] and tcbs.routes[tcbs.routeset].ars then
- tcbs.ars_disabled = true
+ tcbs.ars_ignore_next = true
end
-- if route committed, cancel route ts info
ilrs.update_route(sigd, tcbs, nil, true)
@@ -749,6 +756,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.newroute and hasprivs then
advtrains.interlocking.init_route_prog(pname, sigd)
minetest.close_formspec(pname, formname)
+ tcbs.ars_ignore_next = nil
return
end
if sel_rte and tcbs.routes[sel_rte] then
@@ -778,7 +786,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
ildb.set_sigd_for_signal(signal_pos, nil)
tcbs.signal = nil
tcbs.aspect = nil
- advtrains.interlocking.distant.remove(tcbs)
minetest.close_formspec(pname, formname)
minetest.chat_send_player(pname, "Signal has been unassigned. Name and routes are kept for reuse.")
return
@@ -786,16 +793,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
minetest.chat_send_player(pname, "Please cancel route first!")
end
end
- if fields.influp and hasprivs then
- advtrains.interlocking.show_ip_form(tcbs.signal, pname)
- return
- end
- if tcbs.ars_disabled and fields.arsenable then
- tcbs.ars_disabled = nil
+ if fields.ars then
+ tcbs.ars_disabled = not minetest.is_yes(fields.ars)
end
- if not tcbs.ars_disabled and fields.arsdisable then
- tcbs.ars_disabled = true
+
+ if fields.dst then
+ tcbs.nodst = not minetest.is_yes(fields.dst)
end
if fields.auto then
diff --git a/advtrains_interlocking/train_sections.lua b/advtrains_interlocking/train_sections.lua
index 757f36a..ec7f95f 100644
--- a/advtrains_interlocking/train_sections.lua
+++ b/advtrains_interlocking/train_sections.lua
@@ -91,6 +91,13 @@ local function setsection(tid, train, ts_id, ts, sigd)
tcbs.route_comitted = nil -- TODO compatibility cleanup
tcbs.aspect = nil
tcbs.route_origin = nil
+ if tcbs.signal then
+ local spos = tcbs.signal
+ local _, setter = advtrains.distant.get_main(spos)
+ if setter == "routesetting" then
+ advtrains.distant.unassign_dst(spos, true)
+ end
+ end
advtrains.interlocking.update_signal_aspect(tcbs)
if tcbs.signal and sigd_equal(ts.route.entry, ts.route.origin) then
if tcbs.route_auto and tcbs.routeset then
diff --git a/advtrains_luaautomation/README.md b/advtrains_luaautomation/README.md
index 683e45c..a885075 100644
--- a/advtrains_luaautomation/README.md
+++ b/advtrains_luaautomation/README.md
@@ -255,15 +255,32 @@ In addition to the above environment functions, the following functions are avai
The interlocking system uses this property for Automatic Routesetting.
#### Shunting Functions and Variables
-There are several functions available especially for shunting operations. Some of these functions make use of Freight Codes (FC) set in the Wagon Properties of each wagon and/or locomotive:
+There are several functions available especially for shunting operations.
+Some of these functions make use of Freight Codes (FC) set in the Wagon Properties of each wagon and/or locomotive.
+FCs are composed of codes separated by exclamation marks (`!`), for instance `"foo!bar!baz"`.
+Each wagon has a current FC, indicating its next destination.
- `split_at_index(index, atc_command)`
Splits the train at the specified index, into a train with index-1 wagons and a second train starting with the index-th wagon. The `atc_command` specified is sent to the second train after decoupling. `"S0"` or `"B0"` is common to ensure any locomotives in the remaining train don't continue to move.
+ `index` must be more than 1 to avoid trying to decouple the very front of a train.
+
Example: train has wagons `"foo","foo","foo","bar","bar","bar"`
Command: `split_at_index(4,"S0")`
Result: first train (continues at previous speed): `"foo","foo","foo"`, second train (slows at S0): `"bar","bar","bar"`
+ - `get_fc()`
+ Returns a table with the entire FC list for each wagon in the train.
+ Command: `get_fc()`
+ Result: `{"", "foo!bar", "testing", "fc_1!fc_2!fc_3!?", "hello_world"}`
+
+ - `set_fc(fc_list)`
+ Overwrites the FC list according to a table `fc_list`. A false or nil entry will leave the wagon unaffected, however all others will be overwritten.
+ Useful for mass-programming freight trains that use FC-shunting instead of walking to each wagon individually.
+ Example: train has FC lists: `"", "foo!bar", "testing", "fc_1!fc_2!fc_3!?", "hello_world"`
+ Command: `set_fc({"", "foo!turtle", nil, "4tehlulz", false})`
+ Result: `""` `"foo!turtle"` `"testing"` `"4tehlulz"` `"hello_world"`
+
- `split_at_fc(atc_command, len)`
Splits the train in such a way that all cars with non-empty current FC of the first part of the train have the same FC. The
`atc_command` specified is sent to the rear part, as with split_at_index. It returns the fc of the cars of the first part.
@@ -287,15 +304,11 @@ There are several functions available especially for shunting operations. Some o
first part of the train as above.
- `step_fc()`
- Steps the FCs of all train cars forward. FCs are composed of codes
- separated by exclamation marks (`!`), for instance
- `"foo!bar!baz"`. Each wagon has a current FC, indicating its next
- destination. Stepping the freight code forward, selects the next
- code after the !. If the end of the string is reached, then the
+ Steps the FCs of all train cars forward, selecting the next
+ code after the `!`. If the end of the string is reached, then the
first code is selected, except if the string ends with a question
mark (`?`), then the order is reversed.
-
- `train_length()`
returns the number of cars the train is composed of.
@@ -312,13 +325,16 @@ Deprecated:
#### Interlocking
-This additional function is available when advtrains_interlocking is enabled:
+These additional functions are available when advtrains_interlocking is enabled:
- - `atc_set_disable_ars(boolean)`
+ - `atc_set_ars_disable(boolean)`
Disables (true) or enables (false) the use of ARS for this train. The train will not trigger ARS (automatic route setting) on signals then.
- Note: If you want to disable ARS from an approach callback, the call to `atc_set_disable_ars(true)` *must* happen during the approach callback, and may not be deferred to an interrupt(). Else the train might trigger an ARS before the interrupt fires.
+ Note: If you want to disable ARS from an approach callback, the call to `atc_set_ars_disable(true)` *must* happen during the approach callback, and may not be deferred to an interrupt(). Else the train might trigger an ARS before the interrupt fires.
+ - `section_occupancy(section_id)`
+ Returns a table of train ids for the specified section, nil if no section id is provided, false if the section id is invalid, an empty table if the section id is valid but empty of trains.
+
#### Approach callbacks
The LuaATC interface provides a way to hook into the approach callback system, which is for example used in the TSR rails (provided by advtrains_interlocking) or the station tracks (provided by advtrains_lines). However, for compatibility reasons, this behavior needs to be explicitly enabled.
diff --git a/advtrains_luaautomation/active_common.lua b/advtrains_luaautomation/active_common.lua
index 9bf8377..50fb2bc 100644
--- a/advtrains_luaautomation/active_common.lua
+++ b/advtrains_luaautomation/active_common.lua
@@ -14,7 +14,7 @@ end
function ac.after_place_node(pos, player)
local meta=minetest.get_meta(pos)
meta:set_string("formspec", ac.getform(pos, meta))
- meta:set_string("infotext", "LuaAutomation component, unconfigured.")
+ meta:set_string("infotext", "LuaATC component, unconfigured.")
local ph=minetest.pos_to_string(pos)
--just get first available key!
for en,_ in pairs(atlatc.envs) do
@@ -48,7 +48,7 @@ function ac.getform(pos, meta_p)
.."button[5,0.2;2,1;save;Save]"
.."button[7,0.2;3,1;cle;Clear Local Env.]"
.."textarea[0.3,1.5;"..atlatc.CODE_FORM_SIZE..";code;Code;"..minetest.formspec_escape(code).."]"
- .."label[0,9.7;"..err.."]"
+ .."label["..atlatc.CODE_FORM_ERRLABELPOS..";"..err.."]"
return form
end
@@ -91,17 +91,17 @@ function ac.on_receive_fields(pos, formname, fields, player)
meta:set_string("formspec", ac.getform(pos, meta))
if nodetbl.env then
- meta:set_string("infotext", "LuaAutomation component, assigned to environment '"..nodetbl.env.."'")
+ meta:set_string("infotext", "LuaATC component, assigned to environment '"..nodetbl.env.."'")
else
- meta:set_string("infotext", "LuaAutomation component, invalid enviroment set!")
+ meta:set_string("infotext", "LuaATC component, invalid enviroment set!")
end
end
-function ac.run_in_env(pos, evtdata, customfct_p)
+function ac.run_in_env(pos, evtdata, customfct_p, ignore_no_code)
local ph=minetest.pos_to_string(pos)
local nodetbl = ac.nodes[ph]
if not nodetbl then
- atwarn("LuaAutomation component at",ph,": Data not in memory! Please visit component and click 'Save'!")
+ atwarn("LuaATC component at",ph,": Data not in memory! Please visit component and click 'Save'!")
return
end
@@ -111,12 +111,14 @@ function ac.run_in_env(pos, evtdata, customfct_p)
end
if not nodetbl.env or not atlatc.envs[nodetbl.env] then
- atwarn("LuaAutomation component at",ph,": Not an existing environment: "..(nodetbl.env or "<nil>"))
+ atwarn("LuaATC component at",ph,": Not an existing environment: "..(nodetbl.env or "<nil>"))
return false
end
local env = atlatc.envs[nodetbl.env]
if not nodetbl.code or nodetbl.code=="" then
- env:log("warning", "LuaAutomation component at",ph,": No code to run! (insert -- to suppress warning)")
+ if not ignore_no_code then
+ env:log("warning", "LuaATC component at",ph,": No code to run! (insert -- to suppress warning)")
+ end
return false
end
diff --git a/advtrains_luaautomation/atc_rail.lua b/advtrains_luaautomation/atc_rail.lua
index b862129..aac11f0 100644..100755
--- a/advtrains_luaautomation/atc_rail.lua
+++ b/advtrains_luaautomation/atc_rail.lua
@@ -14,7 +14,7 @@ function r.fire_event(pos, evtdata, appr_internal)
local railtbl = atlatc.active.nodes[ph]
if not railtbl then
- atwarn("LuaAutomation ATC interface rail at",ph,": Data not in memory! Please visit position and click 'Save'!")
+ atwarn("LuaATC interface rail at",ph,": Data not in memory! Please visit position and click 'Save'!")
return
end
@@ -56,7 +56,7 @@ function r.fire_event(pos, evtdata, appr_internal)
split_at_index = function(index, cmd)
if not train_id then return false end
assertt(cmd, "string")
- if type(index) ~= "number" then
+ if type(index) ~= "number" or index < 2 then
return false
end
local new_id = advtrains.split_train_at_index(train, index)
@@ -91,6 +91,38 @@ function r.fire_event(pos, evtdata, appr_internal)
if not train_id then return false end
advtrains.train_step_fc(train)
end,
+ get_fc = function()
+ if not train_id then return end
+ local fc_list = {}
+ for index,wagon_id in ipairs(train.trainparts) do
+ fc_list[index] = table.concat(advtrains.wagons[wagon_id].fc,"!") or ""
+ end
+ return fc_list
+ end,
+ set_fc = function(fc_list)
+ assertt(fc_list, "table")
+ if not train_id then return false end
+ -- safety type-check for entered values
+ for _,v in ipairs(fc_list) do
+ if v and type(v) ~= "string" then
+ error("FC entries must be a string")
+ return
+ end
+ end
+ for index,wagon_id in ipairs(train.trainparts) do
+ if fc_list[index] then -- has FC to enter to this wagon
+ local data = advtrains.wagons[wagon_id]
+ if data then -- wagon actually exists
+ for _,wagon in pairs(minetest.luaentities) do -- find wagon entity
+ if wagon.is_wagon and wagon.initialized and wagon.id==wagon_id then
+ wagon.set_fc(data,fc_list[index]) -- overwrite to new FC
+ break -- no point cycling through every other entity. we found our wagon
+ end
+ end
+ end
+ end
+ end
+ end,
set_shunt = function()
-- enable shunting mode
if not train_id then return false end
@@ -130,9 +162,8 @@ function r.fire_event(pos, evtdata, appr_internal)
get_rc = function()
return train.routingcode
end,
- atc_reset = function(cmd)
+ atc_reset = function()
if not train_id then return false end
- assertt(cmd, "string")
advtrains.atc.train_reset_command(train)
return true
end,
@@ -188,7 +219,7 @@ advtrains.register_tracks("default", {
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_atc.png",
- description=atltrans("LuaAutomation ATC Rail"),
+ description=atltrans("LuaATC Rail"),
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
diff --git a/advtrains_luaautomation/environment.lua b/advtrains_luaautomation/environment.lua
index 63aa68d..d85bedc 100644
--- a/advtrains_luaautomation/environment.lua
+++ b/advtrains_luaautomation/environment.lua
@@ -150,7 +150,7 @@ local static_env = {
--interrupts are handled per node, position unknown. (same goes for digilines)
--however external interrupts can be set here.
interrupt_pos = function(parpos, imesg)
- local pos=atlatc.pcnaming.resolve_pos(parpos)
+ local pos=atlatc.pcnaming.resolve_pos(parpos, "interrupt_pos")
atlatc.interrupt.add(0, pos, {type="ext_int", ext_int=true, message=imesg})
end,
-- sends an atc command to train regardless of where it is in the world
@@ -223,6 +223,15 @@ if advtrains.interlocking then
local pos = atlatc.pcnaming.resolve_pos(signal)
return advtrains.interlocking.signal_set_aspect(pos)
end
+
+ --section_occupancy()
+ static_env.section_occupancy = function(ts_id)
+ if not ts_id then return nil end
+ ts_id = tostring(ts_id)
+ local response = advtrains.interlocking.db.get_ts(ts_id)
+ if not response then return false end
+ return table.copy(response.trains)
+ end
end
-- Lines-specific:
diff --git a/advtrains_luaautomation/init.lua b/advtrains_luaautomation/init.lua
index ab625b1..c51aa71 100644
--- a/advtrains_luaautomation/init.lua
+++ b/advtrains_luaautomation/init.lua
@@ -14,6 +14,8 @@ minetest.register_privilege("atlatc", { description = "Player can place and modi
--Size of code input forms in X,Y notation. Must be at least 10x10
atlatc.CODE_FORM_SIZE = "15,12"
+--Position of Error Label in Code Form
+atlatc.CODE_FORM_ERRLABELPOS = "0,12"
--assertt helper. error if a variable is not of a type
function assertt(var, typ)
@@ -31,6 +33,9 @@ dofile(mp.."/interrupt.lua")
dofile(mp.."/active_common.lua")
dofile(mp.."/atc_rail.lua")
dofile(mp.."/operation_panel.lua")
+if mesecon then
+ dofile(mp.."/mesecon_controller.lua")
+end
dofile(mp.."/pcnaming.lua")
dofile(mp.."/chatcmds.lua")
diff --git a/advtrains_luaautomation/mesecon_controller.lua b/advtrains_luaautomation/mesecon_controller.lua
new file mode 100644
index 0000000..bffff84
--- /dev/null
+++ b/advtrains_luaautomation/mesecon_controller.lua
@@ -0,0 +1,259 @@
+-- mesecon_controller.lua
+-- Mesecon-interfaceable Operation Panel alternative
+-- Looks like a Mesecon Luacontroller
+
+-- Luacontroller Adapted Code
+-- From Mesecons mod https://mesecons.net/
+-- (c) Jeija and Contributors
+
+local BASENAME = "advtrains_luaautomation:mesecon_controller"
+
+local rules = {
+ a = {x = -1, y = 0, z = 0, name="A"},
+ b = {x = 0, y = 0, z = 1, name="B"},
+ c = {x = 1, y = 0, z = 0, name="C"},
+ d = {x = 0, y = 0, z = -1, name="D"},
+}
+
+local function generate_name(ports)
+ local d = ports.d and 1 or 0
+ local c = ports.c and 1 or 0
+ local b = ports.b and 1 or 0
+ local a = ports.a and 1 or 0
+ return BASENAME..d..c..b..a
+end
+
+
+local function set_port(pos, rule, state)
+ if state then
+ mesecon.receptor_on(pos, {rule})
+ else
+ mesecon.receptor_off(pos, {rule})
+ end
+end
+
+local function clean_port_states(ports)
+ ports.a = ports.a and true or false
+ ports.b = ports.b and true or false
+ ports.c = ports.c and true or false
+ ports.d = ports.d and true or false
+end
+
+-- Local table for storing which Mesecons off events should be ignored
+-- Indexed by hex encoded position
+local ignored_off_events = {}
+
+local function set_port_states(pos, ports)
+ local node = advtrains.ndb.get_node(pos)
+ local name = node.name
+ clean_port_states(ports)
+ local vports = minetest.registered_nodes[name].virtual_portstates
+ local new_name = generate_name(ports)
+
+ if name ~= new_name and vports then
+ -- Problem:
+ -- We need to place the new node first so that when turning
+ -- off some port, it won't stay on because the rules indicate
+ -- there is an onstate output port there.
+ -- When turning the output off then, it will however cause feedback
+ -- so that the luacontroller will receive an "off" event by turning
+ -- its output off.
+ -- Solution / Workaround:
+ -- Remember which output was turned off and ignore next "off" event.
+ local ph=minetest.pos_to_string(pos)
+ local railtbl = atlatc.active.nodes[ph]
+ if not railtbl then return end
+
+ local ign = railtbl.ignored_off_events or {}
+ if ports.a and not vports.a and not mesecon.is_powered(pos, rules.a) then ign.A = true end
+ if ports.b and not vports.b and not mesecon.is_powered(pos, rules.b) then ign.B = true end
+ if ports.c and not vports.c and not mesecon.is_powered(pos, rules.c) then ign.C = true end
+ if ports.d and not vports.d and not mesecon.is_powered(pos, rules.d) then ign.D = true end
+ railtbl.ignored_off_events = ign
+
+ advtrains.ndb.swap_node(pos, {name = new_name, param2 = node.param2})
+
+ -- Apply mesecon state only if node loaded
+ -- If node is not loaded, mesecon update will occur on next load via on_updated_from_nodedb
+ if advtrains.is_node_loaded(pos) then
+ if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end
+ if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end
+ if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end
+ if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end
+ end
+ end
+end
+
+local function on_updated_from_nodedb(pos, newnode, oldnode)
+ -- Switch appropriate Mesecon receptors depending on the node change
+ local vports = minetest.registered_nodes[oldnode.name].virtual_portstates
+ local ports = minetest.registered_nodes[newnode.name].virtual_portstates
+ if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end
+ if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end
+ if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end
+ if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end
+end
+
+local function ignore_offevent(pos, rule)
+ local ph=minetest.pos_to_string(pos)
+ local railtbl = atlatc.active.nodes[ph]
+ if not railtbl then return nil end
+ local ign = railtbl.ignored_off_events
+ if ign and ign[rule.name] then
+ ign[rule.name] = nil
+ return true
+ end
+ return false
+end
+
+local valid_ports = {a=true, b=true, c=true, d=true}
+
+local function fire_event(pos, evtdata)
+ local customfct={
+ set_mesecon_outputs = function(states)
+ assertt(states, "table")
+ set_port_states(pos, states)
+ end,
+ get_mesecon_input = function(port)
+ local portl = string.lower(port)
+ if not valid_ports[portl] then
+ error("get_mesecon_input: Invalid port (expected a,b,c,d)")
+ end
+ if mesecon.is_powered(pos, rules[portl]) then
+ return true
+ end
+ return false
+ end,
+ }
+ atlatc.active.run_in_env(pos, evtdata, customfct, true)
+
+end
+
+local output_rules = {}
+local input_rules = {}
+
+local node_box = {
+ type = "fixed",
+ fixed = {
+ {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab
+ {-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board
+ {-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC
+ }
+}
+
+local selection_box = {
+ type = "fixed",
+ fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
+}
+
+for a = 0, 1 do -- 0 = off 1 = on
+for b = 0, 1 do
+for c = 0, 1 do
+for d = 0, 1 do
+ local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a)
+ local node_name = BASENAME..cid
+ local top = "atlatc_luacontroller_top.png"
+ if a == 1 then
+ top = top.."^atlatc_luacontroller_LED_A.png"
+ end
+ if b == 1 then
+ top = top.."^atlatc_luacontroller_LED_B.png"
+ end
+ if c == 1 then
+ top = top.."^atlatc_luacontroller_LED_C.png"
+ end
+ if d == 1 then
+ top = top.."^atlatc_luacontroller_LED_D.png"
+ end
+
+ local groups
+ if a + b + c + d ~= 0 then
+ groups = {dig_immediate=2, not_in_creative_inventory=1, save_in_at_nodedb=1}
+ else
+ groups = {dig_immediate=2, save_in_at_nodedb=1}
+ end
+
+ output_rules[cid] = {}
+ input_rules[cid] = {}
+ if a == 1 then table.insert(output_rules[cid], rules.a) end
+ if b == 1 then table.insert(output_rules[cid], rules.b) end
+ if c == 1 then table.insert(output_rules[cid], rules.c) end
+ if d == 1 then table.insert(output_rules[cid], rules.d) end
+
+ if a == 0 then table.insert( input_rules[cid], rules.a) end
+ if b == 0 then table.insert( input_rules[cid], rules.b) end
+ if c == 0 then table.insert( input_rules[cid], rules.c) end
+ if d == 0 then table.insert( input_rules[cid], rules.d) end
+
+ local mesecons = {
+ effector = {
+ rules = input_rules[cid],
+ action_change = function (pos, _, rule_name, new_state)
+ if new_state == "off" then
+ -- check for ignored off event on this node
+ if ignore_offevent(pos, rule_name) then
+ return
+ end
+ end
+ --Note: rule_name is not a *name* but actually the full rule table (position + name field)
+ --Event format consistent with Mesecons Luacontroller event
+ atlatc.interrupt.add(0, pos, {type=new_state, [new_state]=true, pin=rule_name})
+ end,
+ },
+ receptor = {
+ state = mesecon.state.on,
+ rules = output_rules[cid]
+ },
+ }
+
+ minetest.register_node(node_name, {
+ description = "LuaATC Mesecon Controller",
+ drawtype = "nodebox",
+ tiles = {
+ top,
+ "atlatc_luacontroller_bottom.png",
+ "atlatc_luacontroller_sides.png",
+ "atlatc_luacontroller_sides.png",
+ "atlatc_luacontroller_sides.png",
+ "atlatc_luacontroller_sides.png"
+ },
+ inventory_image = top,
+ paramtype = "light",
+ is_ground_content = false,
+ groups = groups,
+ drop = BASENAME.."0000",
+ sunlight_propagates = true,
+ selection_box = selection_box,
+ node_box = node_box,
+ mesecons = mesecons,
+ -- Virtual portstates are the ports that
+ -- the node shows as powered up (light up).
+ virtual_portstates = {
+ a = a == 1,
+ b = b == 1,
+ c = c == 1,
+ d = d == 1,
+ },
+ after_dig_node = function (pos, node, player)
+ mesecon.receptor_off(pos, output_rules)
+ atlatc.active.after_dig_node(pos, node, player)
+ end,
+ after_place_node = atlatc.active.after_place_node,
+ on_receive_fields = atlatc.active.on_receive_fields,
+ advtrains = {
+ on_updated_from_nodedb = on_updated_from_nodedb
+ },
+ luaautomation = {
+ fire_event=fire_event
+ },
+ digiline = {
+ receptor = {},
+ effector = {
+ action = atlatc.active.on_digiline_receive
+ },
+ },
+ })
+end
+end
+end
+end
diff --git a/advtrains_luaautomation/operation_panel.lua b/advtrains_luaautomation/operation_panel.lua
index f8b93b5..c118ff3 100644..100755
--- a/advtrains_luaautomation/operation_panel.lua
+++ b/advtrains_luaautomation/operation_panel.lua
@@ -1,13 +1,13 @@
-local function on_punch(pos, player)
- atlatc.interrupt.add(0, pos, {type="punch", punch=true})
+local function on_punch(pos,node,player)
+ atlatc.interrupt.add(0, pos, {type="punch", punch=true, name=player:get_player_name()})
end
minetest.register_node("advtrains_luaautomation:oppanel", {
drawtype = "normal",
tiles={"atlatc_oppanel.png"},
- description = "LuaAutomation operation panel",
+ description = "LuaATC operation panel",
groups = {
cracky = 1,
save_in_at_nodedb=1,
diff --git a/advtrains_luaautomation/pcnaming.lua b/advtrains_luaautomation/pcnaming.lua
index ebb769f..71f4d9a 100644
--- a/advtrains_luaautomation/pcnaming.lua
+++ b/advtrains_luaautomation/pcnaming.lua
@@ -44,7 +44,12 @@ minetest.register_craftitem("advtrains_luaautomation:pcnaming",{
return
end
local node = advtrains.ndb.get_node(pos)
- if node.name and (minetest.get_item_group(node.name, "advtrains_signal")>0 or advtrains.is_passive(pos)) then
+ local ndef = minetest.registered_nodes[node.name]
+ if node.name and (
+ minetest.get_item_group(node.name, "advtrains_signal")>0 --is IL signal
+ or advtrains.is_passive(pos) -- is passive component
+ or (ndef and ndef.luaautomation) -- is active component
+ ) then
--look if this one already has a name
local pn=""
for name, npos in pairs(atlatc.pcnaming.name_map) do
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_LED_A.png b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_A.png
new file mode 100644
index 0000000..c6182cc
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_A.png
Binary files differ
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_LED_B.png b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_B.png
new file mode 100644
index 0000000..04c2da0
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_B.png
Binary files differ
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_LED_C.png b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_C.png
new file mode 100644
index 0000000..01f6ae4
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_C.png
Binary files differ
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_LED_D.png b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_D.png
new file mode 100644
index 0000000..6c8a26f
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_LED_D.png
Binary files differ
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_bottom.png b/advtrains_luaautomation/textures/atlatc_luacontroller_bottom.png
new file mode 100644
index 0000000..7ae955c
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_bottom.png
Binary files differ
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_sides.png b/advtrains_luaautomation/textures/atlatc_luacontroller_sides.png
new file mode 100644
index 0000000..40f4b60
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_sides.png
Binary files differ
diff --git a/advtrains_luaautomation/textures/atlatc_luacontroller_top.png b/advtrains_luaautomation/textures/atlatc_luacontroller_top.png
new file mode 100644
index 0000000..a5059af
--- /dev/null
+++ b/advtrains_luaautomation/textures/atlatc_luacontroller_top.png
Binary files differ
diff --git a/advtrains_signals_japan/.gitignore b/advtrains_signals_japan/.gitignore
new file mode 100644
index 0000000..0969b6b
--- /dev/null
+++ b/advtrains_signals_japan/.gitignore
@@ -0,0 +1 @@
+models/*
diff --git a/advtrains_signals_japan/init.lua b/advtrains_signals_japan/init.lua
new file mode 100644
index 0000000..84373a9
--- /dev/null
+++ b/advtrains_signals_japan/init.lua
@@ -0,0 +1,439 @@
+local pole_texture = "advtrains_signals_japan_mast.png"
+local signal_face_texture = "advtrains_hud_bg.png^[colorize:#000000:255"
+local pole_radius = 1/16
+local pole_box = {-pole_radius,-1/2,-pole_radius,pole_radius,1/2,pole_radius}
+local light_radius = 1/20
+local signal_width = 6*light_radius
+local signal_thickness = pole_radius*3
+local signal_height = {}
+local signal_box = {}
+local light_red = "advtrains_hud_bg.png^[colorize:red:255"
+local light_yellow = "advtrains_hud_bg.png^[colorize:orange:255"
+local light_green = "advtrains_hud_bg.png^[colorize:lime:255"
+local light_purple = "advtrains_hud_bg.png^[colorize:purple:255"
+local light_distant = light_purple
+local light_off = signal_face_texture
+
+do
+ local model_path_prefix = table.concat({minetest.get_modpath("advtrains_signals_japan"), "models", "advtrains_signals_japan_"}, DIR_DELIM)
+
+ local function vertex(x, y, z)
+ return string.format("v %f %f %f", x, y, z)
+ end
+ local function texture(u, v)
+ return string.format("vt %f %f", u, v)
+ end
+ local function face_element(v, vt)
+ if vt then
+ return string.format("%d/%d", v, vt)
+ end
+ return tonumber(v)
+ end
+ local function face_elements(...)
+ local st = {"f"}
+ local args = {...}
+ local len = #args
+ for i = 1, len, 2 do
+ st[(i+3)/2] = face_element(args[i], args[i+1])
+ end
+ return table.concat(st, " ")
+ end
+ local function sequential_elements(v0, vt0, count)
+ local st = {}
+ for i = 1, count do
+ st[i] = face_element(v0+i, vt0+i)
+ end
+ return table.concat(st, " ")
+ end
+ local function mod_lower(min, a, b)
+ return min + (a-min)%b
+ end
+ local function connect_circular(v0, vt0, count)
+ return "f " .. sequential_elements(v0, vt0, count)
+ end
+ local function connect_cylindrical(v0, vt0, count)
+ local st = {}
+ for i = 0, count-1 do
+ local j = (i+1)%count
+ local v1 = v0+i+1
+ local v2 = v1+count
+ local v3 = v0+j+1
+ local v4 = v3+count
+ local vt1 = vt0+i+1
+ local vt2 = vt1+count+1
+ st[i+1] = face_elements(v1, vt1, v3, vt1+1, v4, vt2+1, v2, vt2)
+ end
+ return table.concat(st, "\n")
+ end
+ local function circular_textures(u0, v0, r, count, total, angular_offset, direction)
+ local st = {}
+ if not angular_offset then
+ angular_offset = 0
+ end
+ if not total then
+ total = count
+ end
+ if not direction then
+ direction = 1
+ end
+ for i = 0, count-1 do
+ local theta = angular_offset + direction*i/total*2*math.pi
+ local u, v = r*math.cos(theta), r*math.sin(theta)
+ st[i+1] = texture(u0+u, v0+v)
+ end
+ return table.concat(st, "\n")
+ end
+ local function rectangular_textures(u0, v0, u1, v1, count)
+ local st = {}
+ local width = u1-u0
+ for i = 0, count do
+ local u = u0+i/count*width
+ st[i+1] = texture(u, v0)
+ st[i+count+2] = texture(u, v1)
+ end
+ return table.concat(st, "\n")
+ end
+
+ -- generate pole model
+ local pole_npolygon = 32
+ local pole_vertex_count = pole_npolygon*2
+ local pole_uv_count = pole_npolygon*3+2
+ local pole_vertices = {}
+ local pole_objdef = {
+ "g pole",
+ "usemtl pole",
+ connect_circular(0, 0, pole_npolygon),
+ connect_circular(pole_npolygon, 0, pole_npolygon),
+ connect_cylindrical(0, pole_npolygon, pole_npolygon),
+ }
+ local pole_uv = {
+ circular_textures(0.5, 0.5, 0.5, pole_npolygon),
+ rectangular_textures(0, 0, 1, 1, pole_npolygon),
+ }
+ for i = 0, pole_npolygon-1 do
+ local theta = i*2/pole_npolygon*math.pi
+ local r = pole_radius
+ local x, z = r*math.sin(theta), r*math.cos(theta)
+ local lower_index = i+1
+ local upper_index = lower_index+pole_npolygon
+ pole_vertices[lower_index] = vertex(x, -0.5, z)
+ pole_vertices[upper_index] = vertex(x, 0.5, z)
+ end
+ pole_vertices = table.concat(pole_vertices, "\n")
+ pole_objdef = table.concat(pole_objdef, "\n")
+ pole_uv = table.concat(pole_uv, "\n")
+ minetest.safe_file_write(model_path_prefix .. "pole.obj", table.concat({pole_vertices, pole_uv, pole_objdef}, "\n"))
+
+ -- generate signals
+ for lightcount = 5, 6 do
+ for rotname, rot in pairs {["0"] = 0, ["30"] = 26.5, ["45"] = 45, ["60"] = 63.5} do
+ local rot = math.rad(rot)
+ local lightradius = 0.05
+ local lightspacing = 0.04
+ local halfwidth = signal_width/2
+ local halfheight = (2+lightcount)*lightradius+(lightcount-1)*lightspacing/2
+ local halfthickness = signal_thickness/2
+ local half_npolygon = pole_npolygon/2
+ local quarter_npolygon = pole_npolygon/4
+ local boxside = math.max(halfwidth, halfthickness*2)
+ signal_height[lightcount] = halfheight*2
+ signal_box[lightcount] = {-boxside, -halfheight, -boxside, boxside, halfheight, boxside}
+
+ local _vertex = vertex
+ local rv = vector.new(0, rot, 0)
+ local function vertex(x, y, z)
+ local v = vector.rotate(vector.new(x, y, z), rv)
+ return _vertex(v.x, v.y, v.z)
+ end
+
+ -- generate signal face
+ local face_vertices = {}
+ local face_uv = {
+ circular_textures(0.5, 0.5+halfheight-3*lightradius, halfwidth, half_npolygon+1, pole_npolygon),
+ circular_textures(0.5, 0.5-halfheight+3*lightradius, halfwidth, half_npolygon+1, pole_npolygon, math.pi),
+ rectangular_textures(0, 0, 1, 1, 2+pole_npolygon),
+ }
+ local face_objdef = {
+ "g face",
+ "usemtl face",
+ connect_circular(pole_vertex_count+2+pole_npolygon, pole_uv_count, 2+pole_npolygon),
+ connect_circular(pole_vertex_count, pole_uv_count, 2+pole_npolygon),
+ connect_cylindrical(pole_vertex_count, pole_uv_count+2+pole_npolygon, 2+pole_npolygon),
+ }
+ local face_vertex_count = 4*half_npolygon+4
+ local face_uv_count = 2*(half_npolygon+1) + 2*(pole_npolygon+3)
+ for i = 0, half_npolygon do
+ local theta = i/half_npolygon*math.pi
+ local r = halfwidth
+ local x, y = r*math.cos(theta), halfheight-3*lightradius+r*math.sin(theta)
+ face_vertices[i+1] = vertex(x, y, -halfthickness)
+ face_vertices[i+2+half_npolygon] = vertex(-x, -y, -halfthickness)
+ face_vertices[i+3+2*half_npolygon] = vertex(x, y, halfthickness)
+ face_vertices[i+4+3*half_npolygon] = vertex(-x, -y, halfthickness)
+ end
+
+ -- generate lights
+ local light_vertices = {}
+ local light_vertex_count = 8*(half_npolygon+1)+pole_npolygon
+ local light_uv = {rectangular_textures(0, 0, 1, 1, half_npolygon)}
+ local light_uv_count = 2*(half_npolygon+1)+pole_npolygon*lightcount
+ local light_objdef_face = {}
+ local light_objdef_main = {
+ "g light",
+ "usemtl light",
+ }
+ for i = 1, lightcount do
+ local x0, y0 = 0, -halfheight + (2*i+1)*lightradius + (i-1)*lightspacing
+ local v0 = light_vertex_count*(i-1)
+ for j = 0, half_npolygon do
+ local theta = j/half_npolygon*math.pi
+ local xs, ys = math.cos(theta), math.sin(theta)
+ for k, v in pairs {
+ {xm = -1, ym = 1, rm = 1, z = 1},
+ {xm = 1, ym = 1, rm = 0.8, z = 1},
+ {xm = -1, ym = 1, rm = 1, z = 2},
+ {xm = 1, ym = 1, rm = 0.8, z = 2},
+ {xm = 1, ym = -1, rm = 1, z = 1},
+ {xm = -1, ym = -1, rm = 0.8, z = 1},
+ {xm = 1, ym = -1, rm = 1, z = 1.5},
+ {xm = -1, ym = -1, rm = 0.8, z = 1.5},
+ } do
+ local x = x0+xs*lightradius*v.xm*v.rm
+ local y = y0+ys*lightradius*v.ym*v.rm
+ light_vertices[v0+(k-1)*(half_npolygon+1)+j+1] = vertex(x, y, -halfthickness*v.z)
+ end
+ end
+ for j = 0, pole_npolygon-1 do
+ local theta = j/pole_npolygon*2*math.pi
+ local x, y = math.cos(theta), math.sin(theta)
+ light_vertices[v0+8*(half_npolygon+1)+1+j] = vertex(x0+lightradius*x, y0+lightradius*y, -halfthickness*1.05)
+ end
+ local v0 = pole_vertex_count+face_vertex_count+v0
+ local vt0 = pole_uv_count + face_uv_count
+ local ostep = 2*half_npolygon+2
+ for j = 1, half_npolygon do
+ local dv = 2*(half_npolygon+1)
+ local v0 = v0 + dv
+ local vn = v0 + dv
+ light_objdef_face[i*ostep-j+1] = face_elements(v0+j, vt0+j, v0+j+1, vt0+j+1, vn-j, vt0+half_npolygon+2+j, vn-j+1, vt0+half_npolygon+1+j)
+ local v0 = vn + dv
+ local vn = v0 + dv
+ light_objdef_face[i*ostep-half_npolygon-j+1] = face_elements(v0+j, vt0+j, v0+j+1, vt0+j+1, vn-j, vt0+half_npolygon+2+j, vn-j+1, vt0+half_npolygon+1+j)
+ end
+ local vt0 = vt0 + 2*(half_npolygon+1) + (i-1)*pole_npolygon
+ light_uv[i+1] = circular_textures(0.5, (i-1/2)/lightcount, 0.4/lightcount, pole_npolygon)
+ light_objdef_face[(i-1)*ostep+1] = connect_cylindrical(v0, pole_uv_count+2+pole_npolygon, 2+pole_npolygon)
+ light_objdef_face[(i-1)*ostep+2] = connect_cylindrical(v0+4*(half_npolygon+1), pole_uv_count+2+pole_npolygon, 2+pole_npolygon)
+ light_objdef_main[2+i] = connect_circular(v0+8*(half_npolygon+1), vt0, pole_npolygon)
+ end
+
+ -- write file
+ face_vertices = table.concat(face_vertices, "\n")
+ face_uv = table.concat(face_uv, "\n")
+ face_objdef = table.concat(face_objdef, "\n")
+ minetest.safe_file_write(model_path_prefix .. lightcount .. "_" .. rotname .. ".obj", table.concat({
+ pole_vertices,
+ face_vertices,
+ table.concat(light_vertices, "\n"),
+ pole_uv,
+ face_uv,
+ table.concat(light_uv, "\n"),
+ pole_objdef,
+ face_objdef,
+ table.concat(light_objdef_face, "\n"),
+ table.concat(light_objdef_main, "\n"),
+ }, "\n"))
+ end
+ end
+end
+
+local S = attrans
+
+minetest.register_node("advtrains_signals_japan:pole_0", {
+ description = S("Japanese signal pole"),
+ drawtype = "mesh",
+ mesh = "advtrains_signals_japan_pole.obj",
+ tiles = {pole_texture},
+
+ paramtype = "light",
+ sunlight_propagates = true,
+
+ paramtype2 = "none",
+ selection_box = {
+ type = "fixed",
+ fixed = {pole_box},
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = {pole_box},
+ },
+ groups = {
+ cracky = 2,
+ not_blocking_trains = 1,
+ not_in_creative_inventory = 0,
+ },
+ drop = "advtrains_signals_japan:pole_0",
+})
+
+advtrains.interlocking.aspect.register_group {
+ name = "advtrains_signals_japan:5a",
+ label = S("Japanese signal"),
+ aspects = {
+ danger = {
+ label = S"Danger (halt)",
+ main = 0,
+ },
+ restrictedspeed = {
+ label = S"Restricted speed",
+ },
+ caution = {
+ label = S"Caution",
+ },
+ reducedspeed = {
+ label = S"Reduced speed",
+ },
+ clear = {
+ label = S"Clear (proceed)",
+ },
+ "clear",
+ "reducedspeed",
+ "caution",
+ "restrictedspeed",
+ "danger",
+ }
+}
+
+local sigdefs = {}
+local lightcolors = {
+ red = "red",
+ green = "lime",
+ yellow = "orange",
+ distant = "purple",
+}
+local function process_signal(name, sigdata, isrpt)
+ local def = {}
+ local tx = {}
+ def.textures = tx
+ def.desc = sigdata.desc
+ def.isdst = isrpt
+ local lights = sigdata.lights
+ local lightcount = #lights
+ if isrpt then
+ lightcount = lightcount+1
+ end
+ def.lightcount = lightcount
+ def.suppasp_names = {}
+ for idx, asp in ipairs(sigdata.aspects) do
+ local aspname = asp.name
+ local tt = {
+ string.format("[combine:1x%d", lightcount),
+ string.format("0,0=(advtrains_hud_bg.png\\^[resize\\:1x%d\\^[colorize\\:#000)", lightcount),
+ }
+ for _, i in pairs(asp.lights) do
+ local color = lightcolors[lights[i]]
+ tt[#tt+1] = string.format("0,%d=(advtrains_hud_bg.png\\^[colorize\\:%s)", i-1, color)
+ end
+ if isrpt then
+ local color = lightcolors.distant
+ tt[#tt+1] = string.format("0,%d=(advtrains_hud_bg.png\\^[colorize\\:%s)", lightcount-1, color)
+ end
+ tx[aspname] = table.concat(tt, ":")
+ def.suppasp_names[idx] = aspname
+ end
+ local invimg = {
+ string.format("[combine:%dx%d", lightcount*4+1, lightcount*4+1),
+ string.format("%d,0=(advtrains_hud_bg.png\\^[resize\\:5x%d\\^[colorize\\:#000)", lightcount*2-2, lightcount*4+1),
+ }
+ for i, c in pairs(lights) do
+ local color = lightcolors[c]
+ invimg[i+2] = string.format("%d,%d=(advtrains_hud_bg.png\\^[resize\\:3x3\\^[colorize\\:%s)", 2*lightcount-1, 4*i-3, color)
+ end
+ if isrpt then
+ invimg[lightcount+2] = string.format("%d,%d=(advtrains_hud_bg.png\\^[resize\\:3x3\\^[colorize\\:%s)", 2*lightcount-1, 4*lightcount-3, lightcolors.distant)
+ end
+ def.inventory_image = table.concat(invimg, ":")
+ return def
+end
+for sigtype, sigdata in pairs {
+ ["5a"] = {
+ desc = "5A",
+ lights = {"yellow", "yellow", "red", "yellow", "green"},
+ aspects = {
+ {name = "clear", lights = {5}, main = -1},
+ {name = "reducedspeed", lights = {2, 5}},
+ {name = "caution", lights = {4}},
+ {name = "restrictedspeed", lights = {1, 4}},
+ {name = "danger", lights = {3}, main = 0},
+ }
+ }
+} do
+ sigdefs["main_"..sigtype] = process_signal(sigtype, sigdata)
+ sigdefs["rpt_"..sigtype] = process_signal(sigtype, sigdata, true)
+end
+
+for k in pairs(sigdefs) do
+ advtrains.trackplacer.register_tracktype("advtrains_signals_japan:"..k)
+end
+
+for _, rtab in ipairs {
+ {rot = "0", ici = true},
+ {rot = "30"},
+ {rot = "45"},
+ {rot = "60"},
+} do
+ local rot = rtab.rot
+ for sigtype, siginfo in pairs(sigdefs) do
+ local lightcount = siginfo.lightcount
+ for asp, texture in pairs(siginfo.textures) do
+ minetest.register_node("advtrains_signals_japan:"..sigtype.."_"..asp.."_"..rot, {
+ description = attrans(string.format("Japanese%s signal (type %s)", siginfo.isdst and " repeating" or "", siginfo.desc)),
+ drawtype = "mesh",
+ mesh = string.format("advtrains_signals_japan_%d_%s.obj", lightcount, rot),
+ tiles = {pole_texture, signal_face_texture, texture},
+ paramtype = "light",
+ sunlight_propagates = true,
+ light_source = 4,
+ paramtype2 = "facedir",
+ selection_box = {
+ type = "fixed",
+ fixed = {pole_box, signal_box[lightcount]},
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = {pole_box, signal_box[lightcount]},
+ },
+ groups = {
+ cracky = 2,
+ advtrains_signal = 2,
+ not_blocking_trains = 1,
+ save_in_at_nodedb = 1,
+ not_in_creative_inventory = rtab.ici and asp == "danger" and 0 or 1,
+ },
+ inventory_image = siginfo.inventory_image,
+ drop = "advtrains_signals_japan:"..sigtype.."_danger_0",
+ advtrains = {
+ supported_aspects = {
+ group = "advtrains_signals_japan:5a",
+ name = siginfo.suppasp_names,
+ dst_shift = siginfo.isdst and 0,
+ main = (not siginfo.isdst) and {} or false
+ },
+ get_aspect = function()
+ local main
+ if siginfo.isdst then
+ main = false
+ end
+ return {group = "advtrains_signals_japan:5a", name = asp, main = main}
+ end,
+ set_aspect = function(pos, node, asp)
+ advtrains.ndb.swap_node(pos, {name = "advtrains_signals_japan:"..sigtype.."_"..(asp.name).."_"..rot, param2 = node.param2})
+ end,
+ },
+ on_rightclick = advtrains.interlocking.signal_rc_handler,
+ can_dig = advtrains.interlocking.signal_can_dig,
+ after_dig_node = advtrains.interlocking.signal_after_dig,
+ })
+ advtrains.trackplacer.add_worked("advtrains_signals_japan:"..sigtype, asp, "_"..rot)
+ end
+ end
+end
diff --git a/advtrains_signals_japan/textures/advtrains_signals_japan_mast.png b/advtrains_signals_japan/textures/advtrains_signals_japan_mast.png
new file mode 100644
index 0000000..8d288a9
--- /dev/null
+++ b/advtrains_signals_japan/textures/advtrains_signals_japan_mast.png
Binary files differ
diff --git a/advtrains_signals_ks/doc/advtrains_signals_ks.7advtrains.md b/advtrains_signals_ks/doc/advtrains_signals_ks.7advtrains.md
new file mode 100644
index 0000000..126ecf0
--- /dev/null
+++ b/advtrains_signals_ks/doc/advtrains_signals_ks.7advtrains.md
@@ -0,0 +1,52 @@
+% advtrains_signals_ks(7advtrains) | Advtrains User Guide
+
+# NAME
+`advtrains_signals_ks` - Ks signals for advtrains
+
+# DESCRIPTION
+
+This mod includes a modified subset of German rail signals. This page documents the signals implemented by this mod and some differences between this mod and German signals used in real life.
+
+# SIGNAL ASPECTS
+
+This section mainly describes the different signal aspects. Please note that the meaning of some signal aspects may differ from their RL counterparts, and that the differences documented in the following section are not comprehensive.
+
+Due to historical reasons, "ex-DB" and "ex-DR" are used to refer to the former Deutsche Bundesbahn (West Germany) and the former Deutsche Reichsbahn (East Germany), respectively.
+
+## Ks signals
+The Ks signals are used like most other signals in advtrains. It has the following aspects:
+
+* Hp 0 (red light): Stop
+* Ks 1 (green light): Proceed at maximum speed or with the speed limit shown on the Zs 3 indicator directly above the signal (if present) and expect to proceed the next main signal at maximum speed or, if the green light is flashing, with the speed limit shown on the Zs 3v indicator directly below the signal
+* Ks 2 (yellow light): Proceed at maximum speed or with the speed limit shown on the Zs 3 indicator directly above the signal (if present) and expect to stop in front of the next main signal.
+
+In addition, Sh 1 (see below) may also appear with Hp 0, in which case the train continues in shunt mode.
+
+## Shunt signals
+Shunt signals are labeled "Ks Shunting signal" in-game. It has the following aspects:
+
+* Sh 0 (two horizontally aligned red lights): Stop
+* Sh 1/(ex-DR) Ra 12 (two white lights aligned on a slanted line): shunting allowed
+
+## Signal signs
+There are a few signal signs provided by this mod:
+
+* Zs 3 (white number on a black background): Proceed with the permanent speed limit shown on the sign
+* Zs 10 (an sign shaped like an upward-pointing arrow): The speed limit previously set by Zs 3 is lifted
+* Lf 1/2 (black number on an orange background): Proceed with the temporary speed limit shown on the sign
+* Lf 3 (black letter "E" on a white background): The temporary speed limit previously set by Lf 1/2 is lifted
+* Lf 7 (black number on a white background): Proceed with the line speed limit shown on the sign
+* Ra 10 (the black text "Halt für Rangierfahrten" on a white semicircle): Do not proceed if in shunt mode
+* Proceed as main ("PAM", in-game only) ("S" below a green arrow): Proceed without shunt mode
+
+# DIFFERENCES FROM REAL-LIFE SIGNALING
+
+[This document](https://www.bahnstatistik.de/Signale_pdf/SB-DBAG.pdf) is used for reference,
+
+* The speed is indicated in m/s instead of multiples of 10km/h.
+* Due to the potentially large number of nodes, only certain hard-coded values are allowed.
+* Certain visual effects, such as making signal signs reflective or lit at night, are not implemented.
+* Distant signaling is not yet implemented.
+* The location of most signals are not checked. The location of Zs 3 and Zs 3v are only checked relative to the location of the main (Ks) signal.
+* The "shunt signals" in this mod are actually known as "Schutzsignale". The word "Rangiersignale" refers to a different set of signals (including acoustic signals) given by the person specifically responsible for train shunting.
+* The ex-DB definition of Sh 1 ("Fahrverbot aufgehoben") is that the track section ahead is clear and does not imply that the driver is allowed to proceed.
diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua
index 3a2f4d0..ff65697 100755
--- a/advtrains_signals_ks/init.lua
+++ b/advtrains_signals_ks/init.lua
@@ -60,14 +60,16 @@ local setaspectf = function(rot)
end
setzs3v(pos, nil, rot)
else
- if asp.dst == -1 then
+ local dst = asp.dst
+ if not dst or dst == -1 or advtrains.speed.not_lessp(dst, asp.main) then
advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_free_"..rot, param2 = node.param2})
- elseif not asp.dst or asp.dst == 0 then
+ dst = -1
+ elseif dst == 0 then
advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_slow_"..rot, param2 = node.param2})
else
advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_nextslow_"..rot, param2 = node.param2})
end
- setzs3v(pos, asp.dst, rot)
+ setzs3v(pos, dst, rot)
end
end
end
@@ -116,6 +118,8 @@ local suppasp_ra = {
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:hs")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:ra")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign")
+advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign_lf")
+advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign_lf7")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:zs3")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:zs3v")
advtrains.trackplacer.register_tracktype("advtrains_signals_ks:mast")
@@ -246,24 +250,14 @@ for _, rtab in ipairs({
-- rotatable by trackworker
advtrains.trackplacer.add_worked("advtrains_signals_ks:ra", typ, "_"..rot)
end
-
- --Schilder:
- for typ, prts in pairs({
- -- Speed restrictions:
- ["8"] = {asp = { main = 8, shunt = true }, n = "12", ici=true},
- ["12"] = {asp = { main = 12, shunt = true }, n = "16"},
- ["16"] = {asp = { main = 16, shunt = true }, n = "e"},
- -- Speed restriction lifted
- ["e"] = {asp = { main = -1, shunt = true }, n = "hfs"},
- -- Halt for shunt moves:
- ["hfs"] = {asp = { main = false, shunt = false }, n = "pam"},
- ["pam"] = {asp = { main = -1, shunt = false, proceed_as_main = true}, n = "8"},
- }) do
- minetest.register_node("advtrains_signals_ks:sign_"..typ.."_"..rot, {
- description = "Signal Sign",
+
+ -- Schilder:
+ local function register_sign(prefix, typ, nxt, description, mesh, tile2, dtyp, inv, asp)
+ minetest.register_node("advtrains_signals_ks:"..prefix.."_"..typ.."_"..rot, {
+ description = description,
drawtype = "mesh",
- mesh = "advtrains_signals_ks_sign"..(typ == "hfs" and "_hfs" or "").."_smr"..rot..".obj",
- tiles = {"advtrains_signals_ks_signpost.png", "advtrains_signals_ks_sign_"..typ..".png"},
+ mesh = "advtrains_signals_ks_"..mesh.."_smr"..rot..".obj",
+ tiles = {"advtrains_signals_ks_signpost.png", tile2},
paramtype="light",
sunlight_propagates=true,
@@ -279,22 +273,81 @@ for _, rtab in ipairs({
advtrains_signal = 2,
not_blocking_trains = 1,
save_in_at_nodedb = 1,
- not_in_creative_inventory = (rtab.ici and prts.ici) and 0 or 1,
+ not_in_creative_inventory = (rtab.ici and typ == dtyp) and 0 or 1,
},
- drop = "advtrains_signals_ks:sign_8_0",
- inventory_image = "advtrains_signals_ks_sign_8.png",
+ drop = "advtrains_signals_ks:"..prefix.."_"..dtyp.."_0",
+ inventory_image = inv,
advtrains = {
- -- This is a static signal! No set_aspect
- get_aspect = function(pos, node)
- return prts.asp
- end,
+ get_aspect = function() return asp end
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
after_dig_node = advtrains.interlocking.signal_after_dig,
})
-- rotatable by trackworker
- advtrains.trackplacer.add_worked("advtrains_signals_ks:sign", typ, "_"..rot, prts.n)
+ advtrains.trackplacer.add_worked("advtrains_signals_ks:"..prefix, typ, "_"..rot, nxt)
+ end
+
+ for typ, prts in pairs {
+ ["hfs"] = {asp = {main = false, shunt = false}, n = "pam", mesh = "_hfs", owntile = true},
+ ["pam"] = {asp = {main = -1, shunt = false, proceed_as_main = true}, n = "ne4"},
+ ["ne4"] = {asp = {}, n = "ne3x1", mesh="_ne4", owntile = true},
+ ["ne3x1"] = {asp = {}, n = "ne3x2", mesh="_ne3", owntile = true},
+ ["ne3x2"] = {asp = {}, n = "ne3x3", mesh="_ne3", owntile = true},
+ ["ne3x3"] = {asp = {}, n = "ne3x4", mesh="_ne3", owntile = true},
+ ["ne3x4"] = {asp = {}, n = "ne3x5", mesh="_ne3", owntile = true},
+ ["ne3x5"] = {asp = {}, n = "hfs", mesh="_ne3", owntile = true},
+ } do
+ local mesh = prts.mesh or ""
+ local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)"
+ if prts.owntile then
+ tile2 = "advtrains_signals_ks_sign_"..typ..".png"
+ end
+ register_sign("sign", typ, prts.n, "Signal Sign", "sign"..mesh, tile2, "hfs", "advtrains_signals_ks_sign_lf7.png", prts.asp)
+ end
+
+ for typ, prts in pairs {
+ -- Speed restrictions:
+ ["4"] = {asp = { main = 4, shunt = true }, n = "6"},
+ ["6"] = {asp = { main = 6, shunt = true }, n = "8"},
+ ["8"] = {asp = { main = 8, shunt = true }, n = "12"},
+ ["12"] = {asp = { main = 12, shunt = true }, n = "16"},
+ ["16"] = {asp = { main = 16, shunt = true }, n = "e"},
+ -- Speed restriction lifted
+ ["e"] = {asp = { main = -1, shunt = true }, n = "4", mesh = "_zs10"},
+ } do
+ local mesh = tonumber(typ) and "_zs3" or prts.mesh or ""
+ local tile2 = "[combine:40x40:0,0=\\(advtrains_signals_ks_sign_off.png\\^[resize\\:40x40\\):3,-2=advtrains_signals_ks_sign_"..typ..".png^[invert:rgb"
+ if typ == "e" then
+ tile2 = "advtrains_signals_ks_sign_zs10.png"
+ end
+ register_sign("sign", typ, prts.n, "Permanent local speed restriction sign", "sign"..mesh, tile2, "8", "advtrains_signals_ks_sign_8.png^[invert:rgb", prts.asp)
+ end
+
+ for typ, prts in pairs {
+ ["4"] = {main = 4, n = "6"},
+ ["6"] = {main = 6, n = "8"},
+ ["8"] = {main = 8, n = "12"},
+ ["12"] = {main = 12, n = "16"},
+ ["16"] = {main = 16, n = "e"},
+ ["e"] = {main = -1, n = "4"},
+ } do
+ local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)"..(typ == "e" and "" or "^[multiply:orange")
+ local inv = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_8.png^[makealpha:255,255,255)^[multiply:orange"
+ register_sign("sign_lf", typ, prts.n, "Temporary local speed restriction sign", "sign", tile2, "8", inv, {main = prts.main, shunt = true, type = "temp"})
+ end
+
+ for typ, prts in pairs {
+ ["4"] = {main = 4, n = "6"},
+ ["6"] = {main = 6, n = "8"},
+ ["8"] = {main = 8, n = "12"},
+ ["12"] = {main = 12, n = "16"},
+ ["16"] = {main = 16, n = "20"},
+ ["20"] = {main = 20, n = "4"},
+ } do
+ local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)"
+ local inv = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_8.png^[makealpha:255,255,255)"
+ register_sign("sign_lf7", typ, prts.n, "Line speed restriction sign", "sign", tile2, "8", inv, {main = prts.main, shunt = true, type = "line"})
end
-- Geschwindigkeits(vor)anzeiger für Ks-Signale
@@ -308,7 +361,7 @@ for _, rtab in ipairs({
}) do
local def = {
drawtype = "mesh",
- tiles = {"advtrains_signals_ks_mast.png","advtrains_signals_ks_head.png","[combine:128x128:0,4=advtrains_signals_ks_zs3_"..typ..".png^[noalpha"},
+ tiles = {"advtrains_signals_ks_mast.png","advtrains_signals_ks_head.png","advtrains_signals_ks_sign_"..typ..".png^[invert:rgb^[noalpha"},
paramtype = "light",
sunlight_propagates = true,
light_source = 4,
@@ -414,3 +467,23 @@ minetest.register_craft({
},
})
sign_material = nil
+
+minetest.register_craft{
+ output = "advtrains_signals_ks:sign_8_0 1",
+ recipe = {{"advtrains_signals_ks:sign_lf7_8_0"}}
+}
+
+minetest.register_craft{
+ output = "advtrains_signals_ks:sign_hfs_0 1",
+ recipe = {{"advtrains_signals_ks:sign_8_0"}}
+}
+
+minetest.register_craft{
+ output = "advtrains_signals_ks:sign_lf_8_0 1",
+ recipe = {{"advtrains_signals_ks:sign_hfs_0"}}
+}
+
+minetest.register_craft{
+ output = "advtrains_signals_ks:sign_lf7_8_0 1",
+ recipe = {{"advtrains_signals_ks:sign_lf_8_0"}}
+}
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr0.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr0.obj
new file mode 100644
index 0000000..01bc666
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr0.obj
@@ -0,0 +1,212 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne3_smr0.mtl
+o Cube.001
+v 0.100000 1.200000 -0.324543
+v 0.100000 1.200000 -0.344543
+v -0.100000 1.200000 -0.344543
+v -0.100000 1.200000 -0.324543
+v -0.100000 0.700000 -0.324543
+v 0.100000 0.700000 -0.324543
+v 0.100000 0.700000 -0.344543
+v -0.100000 0.700000 -0.344543
+v 0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.334802
+v 0.000000 1.055075 -0.334802
+v 0.024805 1.055075 -0.324528
+v -0.035079 1.055075 -0.299723
+v -0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.274918
+v -0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v 0.035079 1.055075 -0.299723
+v 0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.324528
+v -0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.264644
+v 0.000000 1.055075 -0.264644
+v 0.024805 -0.499729 -0.274918
+v 0.035080 -0.499729 -0.299723
+v 0.000000 -0.499729 -0.264644
+v 0.024805 -0.499729 -0.324528
+v 0.000000 -0.499729 -0.334802
+v -0.024804 -0.499729 -0.274918
+v -0.024804 -0.499729 -0.324528
+v -0.035079 -0.499729 -0.299723
+v 0.100000 1.150000 -0.344543
+v 0.100000 1.100000 -0.344543
+v 0.100000 1.050000 -0.344543
+v 0.100000 1.000000 -0.344543
+v 0.100000 0.950000 -0.344543
+v 0.100000 0.900000 -0.344543
+v 0.100000 0.850000 -0.344543
+v 0.100000 0.800000 -0.344543
+v 0.100000 0.750000 -0.344543
+v -0.100000 1.150000 -0.344543
+v -0.100000 1.100000 -0.344543
+v -0.100000 1.050000 -0.344543
+v -0.100000 1.000000 -0.344543
+v -0.100000 0.950000 -0.344543
+v -0.100000 0.900000 -0.344543
+v -0.100000 0.850000 -0.344543
+v -0.100000 0.800000 -0.344543
+v -0.100000 0.750000 -0.344543
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.125000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.125000 0.750000
+vt 0.583333 0.000000
+vt 0.562500 0.250000
+vt 0.541666 0.250000
+vt 0.520833 0.250000
+vt 0.500000 0.250000
+vt 0.479166 0.250000
+vt 0.458333 0.250000
+vt 0.437500 0.250000
+vt 0.416667 0.250000
+vt 0.395833 0.250000
+vt 0.375000 0.250000
+vt 0.375000 0.000000
+vt 0.541666 0.500000
+vt 0.562500 0.500000
+vt 0.395833 0.500000
+vt 0.416667 0.500000
+vt 0.437500 0.500000
+vt 0.458333 0.500000
+vt 0.479166 0.500000
+vt 0.500000 0.500000
+vt 0.520833 0.500000
+vt 0.375000 1.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.812500 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.937500
+vt 0.000000 0.875000
+vt 0.812500 0.875000
+vt 0.812500 0.937500
+vt 0.000000 0.812500
+vt 0.812500 0.812500
+vt 0.000000 0.750000
+vt 0.812500 0.750000
+vt 0.000000 0.687500
+vt 0.812500 0.687500
+vt 0.000000 0.625000
+vt 0.812500 0.625000
+vt 0.000000 0.562500
+vt 0.812500 0.562500
+vt 0.000000 0.500000
+vt 0.812500 0.500000
+vt 0.000000 0.437500
+vt 0.812500 0.437500
+vt 0.000000 0.375000
+vt 0.812500 0.375000
+vt 0.812500 1.000000
+vt 0.000000 0.937500
+vt 0.812500 0.937500
+vn 0.9239 0.3827 -0.0000
+vn -0.0000 0.3826 -0.9239
+vn -0.9239 0.3827 -0.0001
+vn 0.0000 0.3827 0.9239
+vn 0.7071 -0.7071 0.0000
+vn -0.7071 -0.7071 -0.0000
+vn -1.0000 0.0000 0.0000
+vn 1.0000 0.0000 0.0000
+vn 0.0000 -0.0000 1.0000
+vn 0.0000 1.0000 0.0000
+vn 0.9239 0.0000 0.3827
+vn 0.3827 -0.0000 0.9239
+vn 0.3827 0.0000 -0.9239
+vn 0.9239 0.0000 -0.3827
+vn -0.3827 -0.0000 0.9239
+vn -0.9239 -0.0000 -0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn -0.3952 0.8351 -0.3827
+vn 0.0000 0.0000 -1.0000
+vn 0.0000 0.7071 -0.7071
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 8/5/5 7/6/6 6/7/6 5/8/5
+f 4/9/7 3/3/7 42/10/7 43/11/7 44/12/7 45/13/7 46/14/7 47/15/7 48/16/7 49/17/7 50/18/7 8/19/7 5/20/7
+f 34/21/8 33/22/8 2/2/8 1/1/8 6/7/8 7/6/8 41/23/8 40/24/8 39/25/8 38/26/8 37/27/8 36/28/8 35/29/8
+f 1/1/9 4/4/9 5/30/9 6/7/9
+s 1
+f 9/31/9 10/32/9 11/33/9 12/34/9
+f 13/35/9 14/36/9 15/37/9 16/38/9
+f 17/39/9 18/40/9 19/41/9 20/42/9
+f 10/32/9 21/43/9 22/44/9 11/33/9
+f 14/36/9 23/45/9 24/46/9 15/37/9
+f 18/40/9 9/31/9 12/34/9 19/41/9
+f 21/47/10 13/48/10 14/49/10 23/50/10 17/51/10 18/52/10 9/53/10 10/54/10
+f 20/55/11 25/56/11 26/57/11 19/58/11
+f 21/43/9 13/35/9 16/38/9 22/44/9
+f 23/45/9 17/39/9 20/42/9 24/46/9
+f 24/59/12 27/60/12 25/56/12 20/55/12
+f 12/61/13 28/62/13 29/63/13 11/64/13
+f 19/58/14 26/57/14 28/62/14 12/61/14
+f 15/65/15 30/66/15 27/67/15 24/68/15
+f 22/69/16 31/70/16 32/71/16 16/72/16
+f 16/72/17 32/71/17 30/66/17 15/65/17
+f 11/64/18 29/63/18 31/70/18 22/69/18
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 3/73/19 2/74/20 33/75/20
+f 34/76/20 42/77/20 3/78/20 33/75/20
+f 35/79/20 43/80/20 42/77/20 34/76/20
+f 36/81/20 44/82/20 43/80/20 35/79/20
+f 37/83/20 45/84/20 44/82/20 36/81/20
+f 38/85/20 46/86/20 45/84/20 37/83/20
+f 39/87/20 47/88/20 46/86/20 38/85/20
+f 40/89/20 48/90/20 47/88/20 39/87/20
+f 41/91/20 49/92/20 48/90/20 40/89/20
+f 7/93/20 50/94/20 49/92/20 41/91/20
+f 50/95/20 7/96/20 8/97/21
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr30.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr30.obj
new file mode 100644
index 0000000..a20c0bf
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr30.obj
@@ -0,0 +1,213 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne3_smr30.mtl
+o Cube.001
+v 0.234304 1.200000 -0.245825
+v 0.243228 1.200000 -0.263724
+v 0.064241 1.200000 -0.352963
+v 0.055317 1.200000 -0.335064
+v 0.055317 0.700000 -0.335064
+v 0.234304 0.700000 -0.245825
+v 0.243228 0.700000 -0.263724
+v 0.064241 0.700000 -0.352963
+v 0.167003 1.055075 -0.279363
+v 0.149388 1.055075 -0.299626
+v 0.149388 1.055075 -0.299626
+v 0.167003 1.055075 -0.279363
+v 0.102342 1.055075 -0.283885
+v 0.100469 1.055075 -0.257101
+v 0.100469 1.055075 -0.257101
+v 0.102342 1.055075 -0.283885
+v 0.144867 1.055075 -0.234966
+v 0.165129 1.055075 -0.252580
+v 0.165129 1.055075 -0.252580
+v 0.144867 1.055075 -0.234966
+v 0.122605 1.055075 -0.301499
+v 0.122605 1.055075 -0.301499
+v 0.118084 1.055075 -0.236839
+v 0.118084 1.055075 -0.236839
+v 0.144867 -0.499729 -0.234966
+v 0.165130 -0.499729 -0.252580
+v 0.118084 -0.499729 -0.236839
+v 0.167003 -0.499729 -0.279363
+v 0.149388 -0.499729 -0.299626
+v 0.100470 -0.499729 -0.257101
+v 0.122606 -0.499729 -0.301499
+v 0.102342 -0.499729 -0.283885
+v 0.243228 1.150000 -0.263724
+v 0.243228 1.100000 -0.263724
+v 0.243228 1.050000 -0.263724
+v 0.243228 1.000000 -0.263724
+v 0.243228 0.950000 -0.263724
+v 0.243228 0.900000 -0.263724
+v 0.243228 0.850000 -0.263724
+v 0.243228 0.800000 -0.263724
+v 0.243228 0.750000 -0.263724
+v 0.064241 1.150000 -0.352963
+v 0.064241 1.100000 -0.352963
+v 0.064241 1.050000 -0.352963
+v 0.064241 1.000000 -0.352963
+v 0.064241 0.950000 -0.352963
+v 0.064241 0.900000 -0.352963
+v 0.064241 0.850000 -0.352963
+v 0.064241 0.800000 -0.352963
+v 0.064241 0.750000 -0.352963
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.125000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.125000 0.750000
+vt 0.583333 0.000000
+vt 0.562500 0.250000
+vt 0.541666 0.250000
+vt 0.520833 0.250000
+vt 0.500000 0.250000
+vt 0.479166 0.250000
+vt 0.458333 0.250000
+vt 0.437500 0.250000
+vt 0.416667 0.250000
+vt 0.395833 0.250000
+vt 0.375000 0.250000
+vt 0.375000 0.000000
+vt 0.541666 0.500000
+vt 0.562500 0.500000
+vt 0.395833 0.500000
+vt 0.416667 0.500000
+vt 0.437500 0.500000
+vt 0.458333 0.500000
+vt 0.479166 0.500000
+vt 0.500000 0.500000
+vt 0.520833 0.500000
+vt 0.375000 1.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.812500 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.937500
+vt 0.000000 0.875000
+vt 0.812500 0.875000
+vt 0.812500 0.937500
+vt 0.000000 0.812500
+vt 0.812500 0.812500
+vt 0.000000 0.750000
+vt 0.812500 0.750000
+vt 0.000000 0.687500
+vt 0.812500 0.687500
+vt 0.000000 0.625000
+vt 0.812500 0.625000
+vt 0.000000 0.562500
+vt 0.812500 0.562500
+vt 0.000000 0.500000
+vt 0.812500 0.500000
+vt 0.000000 0.437500
+vt 0.812500 0.437500
+vt 0.000000 0.375000
+vt 0.812500 0.375000
+vt 0.812500 1.000000
+vt 0.000000 0.937500
+vt 0.812500 0.937500
+vn 0.8268 0.3827 0.4122
+vn 0.4122 0.3826 -0.8269
+vn -0.8268 0.3827 -0.4123
+vn -0.4122 0.3827 0.8268
+vn 0.6328 -0.7071 0.3155
+vn -0.6328 -0.7071 -0.3155
+vn -0.8949 -0.0000 -0.4462
+vn 0.8949 -0.0000 0.4462
+vn -0.4462 -0.0000 0.8949
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.6561 0.0000 0.7547
+vn -0.0698 -0.0000 0.9976
+vn 0.7547 0.0000 -0.6561
+vn 0.9976 0.0000 0.0698
+vn -0.7547 -0.0000 0.6561
+vn -0.6561 -0.0000 -0.7547
+vn -0.9976 -0.0000 -0.0698
+vn 0.0698 -0.0000 -0.9976
+vn -0.1830 0.8351 -0.5188
+vn 0.4462 0.0000 -0.8949
+vn 0.3155 0.7071 -0.6328
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 8/5/5 7/6/6 6/7/6 5/8/5
+f 4/9/7 3/3/7 42/10/7 43/11/7 44/12/7 45/13/7 46/14/7 47/15/7 48/16/7 49/17/7 50/18/7 8/19/7 5/20/7
+f 34/21/8 33/22/8 2/2/8 1/1/8 6/7/8 7/6/8 41/23/8 40/24/8 39/25/8 38/26/8 37/27/8 36/28/8 35/29/8
+f 1/1/9 4/4/9 5/30/9 6/7/9
+s 1
+f 9/31/10 10/32/10 11/33/10 12/34/10
+f 13/35/10 14/36/10 15/37/10 16/38/10
+f 17/39/10 18/40/10 19/41/10 20/42/10
+f 10/32/10 21/43/10 22/44/10 11/33/10
+f 14/36/10 23/45/10 24/46/10 15/37/10
+f 18/40/10 9/31/10 12/34/10 19/41/10
+f 21/47/11 13/48/11 14/49/11 23/50/11 17/51/11 18/52/11 9/53/11 10/54/11
+f 20/55/12 25/56/12 26/57/12 19/58/12
+f 21/43/10 13/35/10 16/38/10 22/44/10
+f 23/45/10 17/39/10 20/42/10 24/46/10
+f 24/59/13 27/60/13 25/56/13 20/55/13
+f 12/61/14 28/62/14 29/63/14 11/64/14
+f 19/58/15 26/57/15 28/62/15 12/61/15
+f 15/65/16 30/66/16 27/67/16 24/68/16
+f 22/69/17 31/70/17 32/71/17 16/72/17
+f 16/72/18 32/71/18 30/66/18 15/65/18
+f 11/64/19 29/63/19 31/70/19 22/69/19
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 3/73/20 2/74/21 33/75/21
+f 34/76/21 42/77/21 3/78/21 33/75/21
+f 35/79/21 43/80/21 42/77/21 34/76/21
+f 36/81/21 44/82/21 43/80/21 35/79/21
+f 37/83/21 45/84/21 44/82/21 36/81/21
+f 38/85/21 46/86/21 45/84/21 37/83/21
+f 39/87/21 47/88/21 46/86/21 38/85/21
+f 40/89/21 48/90/21 47/88/21 39/87/21
+f 41/91/21 49/92/21 48/90/21 40/89/21
+f 7/93/21 50/94/21 49/92/21 41/91/21
+f 50/95/21 7/96/21 8/97/22
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr45.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr45.obj
new file mode 100644
index 0000000..ed1047b
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr45.obj
@@ -0,0 +1,213 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne3_smr45.mtl
+o Cube.001
+v 0.300197 1.200000 -0.158776
+v 0.314339 1.200000 -0.172918
+v 0.172918 1.200000 -0.314339
+v 0.158776 1.200000 -0.300197
+v 0.158776 0.700000 -0.300197
+v 0.300197 0.700000 -0.158776
+v 0.314339 0.700000 -0.172918
+v 0.172918 0.700000 -0.314339
+v 0.247016 1.055075 -0.211936
+v 0.236741 1.055075 -0.236741
+v 0.236741 1.055075 -0.236741
+v 0.247016 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.176857 1.055075 -0.211936
+v 0.176857 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.211936 1.055075 -0.176857
+v 0.236741 1.055075 -0.187132
+v 0.236741 1.055075 -0.187132
+v 0.211936 1.055075 -0.176857
+v 0.211936 1.055075 -0.247016
+v 0.211936 1.055075 -0.247016
+v 0.187132 1.055075 -0.187132
+v 0.187132 1.055075 -0.187132
+v 0.211936 -0.499729 -0.176857
+v 0.236741 -0.499729 -0.187131
+v 0.187132 -0.499729 -0.187132
+v 0.247016 -0.499729 -0.211936
+v 0.236741 -0.499729 -0.236741
+v 0.176857 -0.499729 -0.211935
+v 0.211937 -0.499729 -0.247015
+v 0.187132 -0.499729 -0.236741
+v 0.314339 1.150000 -0.172918
+v 0.314339 1.100000 -0.172918
+v 0.314339 1.050000 -0.172918
+v 0.314339 1.000000 -0.172918
+v 0.314339 0.950000 -0.172918
+v 0.314339 0.900000 -0.172918
+v 0.314339 0.850000 -0.172918
+v 0.314339 0.800000 -0.172918
+v 0.314339 0.750000 -0.172918
+v 0.172918 1.150000 -0.314339
+v 0.172918 1.100000 -0.314339
+v 0.172918 1.050000 -0.314339
+v 0.172918 1.000000 -0.314339
+v 0.172918 0.950000 -0.314339
+v 0.172918 0.900000 -0.314339
+v 0.172918 0.850000 -0.314339
+v 0.172918 0.800000 -0.314339
+v 0.172918 0.750000 -0.314339
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.125000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.125000 0.750000
+vt 0.583333 0.000000
+vt 0.562500 0.250000
+vt 0.541666 0.250000
+vt 0.520833 0.250000
+vt 0.500000 0.250000
+vt 0.479166 0.250000
+vt 0.458333 0.250000
+vt 0.437500 0.250000
+vt 0.416667 0.250000
+vt 0.395833 0.250000
+vt 0.375000 0.250000
+vt 0.375000 0.000000
+vt 0.541666 0.500000
+vt 0.562500 0.500000
+vt 0.395833 0.500000
+vt 0.416667 0.500000
+vt 0.437500 0.500000
+vt 0.458333 0.500000
+vt 0.479166 0.500000
+vt 0.500000 0.500000
+vt 0.520833 0.500000
+vt 0.375000 1.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.812500 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.937500
+vt 0.000000 0.875000
+vt 0.812500 0.875000
+vt 0.812500 0.937500
+vt 0.000000 0.812500
+vt 0.812500 0.812500
+vt 0.000000 0.750000
+vt 0.812500 0.750000
+vt 0.000000 0.687500
+vt 0.812500 0.687500
+vt 0.000000 0.625000
+vt 0.812500 0.625000
+vt 0.000000 0.562500
+vt 0.812500 0.562500
+vt 0.000000 0.500000
+vt 0.812500 0.500000
+vt 0.000000 0.437500
+vt 0.812500 0.437500
+vt 0.000000 0.375000
+vt 0.812500 0.375000
+vt 0.812500 1.000000
+vt 0.000000 0.937500
+vt 0.812500 0.937500
+vn 0.6533 0.3827 0.6532
+vn 0.6533 0.3826 -0.6533
+vn -0.6532 0.3827 -0.6533
+vn -0.6532 0.3827 0.6533
+vn 0.5000 -0.7071 0.5000
+vn -0.5000 -0.7071 -0.5000
+vn -0.7071 0.0000 -0.7071
+vn 0.7071 0.0000 0.7071
+vn -0.7071 -0.0000 0.7071
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.3827 0.0000 0.9239
+vn -0.3827 -0.0000 0.9239
+vn 0.9239 0.0000 -0.3827
+vn 0.9239 0.0000 0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn -0.9239 -0.0000 -0.3827
+vn 0.3827 -0.0000 -0.9239
+vn -0.0089 0.8351 -0.5501
+vn 0.7071 0.0000 -0.7071
+vn 0.5000 0.7071 -0.5000
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 8/5/5 7/6/6 6/7/6 5/8/5
+f 4/9/7 3/3/7 42/10/7 43/11/7 44/12/7 45/13/7 46/14/7 47/15/7 48/16/7 49/17/7 50/18/7 8/19/7 5/20/7
+f 34/21/8 33/22/8 2/2/8 1/1/8 6/7/8 7/6/8 41/23/8 40/24/8 39/25/8 38/26/8 37/27/8 36/28/8 35/29/8
+f 1/1/9 4/4/9 5/30/9 6/7/9
+s 1
+f 9/31/10 10/32/10 11/33/10 12/34/10
+f 13/35/10 14/36/10 15/37/10 16/38/10
+f 17/39/10 18/40/10 19/41/10 20/42/10
+f 10/32/10 21/43/10 22/44/10 11/33/10
+f 14/36/10 23/45/10 24/46/10 15/37/10
+f 18/40/10 9/31/10 12/34/10 19/41/10
+f 21/47/11 13/48/11 14/49/11 23/50/11 17/51/11 18/52/11 9/53/11 10/54/11
+f 20/55/12 25/56/12 26/57/12 19/58/12
+f 21/43/10 13/35/10 16/38/10 22/44/10
+f 23/45/10 17/39/10 20/42/10 24/46/10
+f 24/59/13 27/60/13 25/56/13 20/55/13
+f 12/61/14 28/62/14 29/63/14 11/64/14
+f 19/58/15 26/57/15 28/62/15 12/61/15
+f 15/65/16 30/66/16 27/67/16 24/68/16
+f 22/69/17 31/70/17 32/71/17 16/72/17
+f 16/72/18 32/71/18 30/66/18 15/65/18
+f 11/64/19 29/63/19 31/70/19 22/69/19
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 3/73/20 2/74/21 33/75/21
+f 34/76/21 42/77/21 3/78/21 33/75/21
+f 35/79/21 43/80/21 42/77/21 34/76/21
+f 36/81/21 44/82/21 43/80/21 35/79/21
+f 37/83/21 45/84/21 44/82/21 36/81/21
+f 38/85/21 46/86/21 45/84/21 37/83/21
+f 39/87/21 47/88/21 46/86/21 38/85/21
+f 40/89/21 48/90/21 47/88/21 39/87/21
+f 41/91/21 49/92/21 48/90/21 40/89/21
+f 7/93/21 50/94/21 49/92/21 41/91/21
+f 50/95/21 7/96/21 8/97/22
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr60.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr60.obj
new file mode 100644
index 0000000..0a28ff1
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne3_smr60.obj
@@ -0,0 +1,213 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne3_smr60.mtl
+o Cube.001
+v 0.335064 1.200000 -0.055317
+v 0.352963 1.200000 -0.064241
+v 0.263724 1.200000 -0.243228
+v 0.245825 1.200000 -0.234304
+v 0.245825 0.700000 -0.234304
+v 0.335064 0.700000 -0.055317
+v 0.352963 0.700000 -0.064241
+v 0.263724 0.700000 -0.243228
+v 0.301499 1.055075 -0.122605
+v 0.299626 1.055075 -0.149388
+v 0.299626 1.055075 -0.149388
+v 0.301499 1.055075 -0.122605
+v 0.252580 1.055075 -0.165129
+v 0.234966 1.055075 -0.144867
+v 0.234966 1.055075 -0.144867
+v 0.252580 1.055075 -0.165129
+v 0.257101 1.055075 -0.100469
+v 0.283885 1.055075 -0.102342
+v 0.283885 1.055075 -0.102342
+v 0.257101 1.055075 -0.100469
+v 0.279363 1.055075 -0.167002
+v 0.279363 1.055075 -0.167002
+v 0.236839 1.055075 -0.118084
+v 0.236839 1.055075 -0.118084
+v 0.257102 -0.499729 -0.100469
+v 0.283885 -0.499729 -0.102341
+v 0.236839 -0.499729 -0.118084
+v 0.301499 -0.499729 -0.122605
+v 0.299626 -0.499729 -0.149388
+v 0.234966 -0.499729 -0.144866
+v 0.279364 -0.499729 -0.167002
+v 0.252580 -0.499729 -0.165129
+v 0.352963 1.150000 -0.064241
+v 0.352963 1.100000 -0.064241
+v 0.352963 1.050000 -0.064241
+v 0.352963 1.000000 -0.064241
+v 0.352963 0.950000 -0.064241
+v 0.352963 0.900000 -0.064241
+v 0.352963 0.850000 -0.064241
+v 0.352963 0.800000 -0.064241
+v 0.352963 0.750000 -0.064241
+v 0.263724 1.150000 -0.243228
+v 0.263724 1.100000 -0.243228
+v 0.263724 1.050000 -0.243228
+v 0.263724 1.000000 -0.243228
+v 0.263724 0.950000 -0.243228
+v 0.263724 0.900000 -0.243228
+v 0.263724 0.850000 -0.243228
+v 0.263724 0.800000 -0.243228
+v 0.263724 0.750000 -0.243228
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.125000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.125000 0.750000
+vt 0.583333 0.000000
+vt 0.562500 0.250000
+vt 0.541666 0.250000
+vt 0.520833 0.250000
+vt 0.500000 0.250000
+vt 0.479166 0.250000
+vt 0.458333 0.250000
+vt 0.437500 0.250000
+vt 0.416667 0.250000
+vt 0.395833 0.250000
+vt 0.375000 0.250000
+vt 0.375000 0.000000
+vt 0.541666 0.500000
+vt 0.562500 0.500000
+vt 0.395833 0.500000
+vt 0.416667 0.500000
+vt 0.437500 0.500000
+vt 0.458333 0.500000
+vt 0.479166 0.500000
+vt 0.500000 0.500000
+vt 0.520833 0.500000
+vt 0.375000 1.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.812500 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.937500
+vt 0.000000 0.875000
+vt 0.812500 0.875000
+vt 0.812500 0.937500
+vt 0.000000 0.812500
+vt 0.812500 0.812500
+vt 0.000000 0.750000
+vt 0.812500 0.750000
+vt 0.000000 0.687500
+vt 0.812500 0.687500
+vt 0.000000 0.625000
+vt 0.812500 0.625000
+vt 0.000000 0.562500
+vt 0.812500 0.562500
+vt 0.000000 0.500000
+vt 0.812500 0.500000
+vt 0.000000 0.437500
+vt 0.812500 0.437500
+vt 0.000000 0.375000
+vt 0.812500 0.375000
+vt 0.812500 1.000000
+vt 0.000000 0.937500
+vt 0.812500 0.937500
+vn 0.4123 0.3827 0.8268
+vn 0.8268 0.3826 -0.4123
+vn -0.4122 0.3827 -0.8268
+vn -0.8268 0.3827 0.4123
+vn 0.3155 -0.7071 0.6328
+vn -0.3155 -0.7071 -0.6328
+vn -0.4462 0.0000 -0.8949
+vn 0.4462 0.0000 0.8949
+vn -0.8949 -0.0000 0.4462
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 0.0000
+vn 0.0698 0.0000 0.9976
+vn -0.6561 -0.0000 0.7547
+vn 0.9976 0.0000 -0.0698
+vn 0.7547 0.0000 0.6561
+vn -0.9976 -0.0000 0.0698
+vn -0.0698 -0.0000 -0.9976
+vn -0.7547 -0.0000 -0.6561
+vn 0.6561 -0.0000 -0.7547
+vn 0.1661 0.8351 -0.5245
+vn 0.8949 0.0000 -0.4462
+vn 0.6328 0.7071 -0.3155
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 8/5/5 7/6/6 6/7/6 5/8/5
+f 4/9/7 3/3/7 42/10/7 43/11/7 44/12/7 45/13/7 46/14/7 47/15/7 48/16/7 49/17/7 50/18/7 8/19/7 5/20/7
+f 34/21/8 33/22/8 2/2/8 1/1/8 6/7/8 7/6/8 41/23/8 40/24/8 39/25/8 38/26/8 37/27/8 36/28/8 35/29/8
+f 1/1/9 4/4/9 5/30/9 6/7/9
+s 1
+f 9/31/10 10/32/10 11/33/10 12/34/10
+f 13/35/10 14/36/10 15/37/10 16/38/10
+f 17/39/10 18/40/10 19/41/10 20/42/10
+f 10/32/10 21/43/10 22/44/10 11/33/10
+f 14/36/10 23/45/10 24/46/10 15/37/10
+f 18/40/10 9/31/10 12/34/10 19/41/10
+f 21/47/11 13/48/11 14/49/11 23/50/11 17/51/11 18/52/11 9/53/11 10/54/11
+f 20/55/12 25/56/12 26/57/12 19/58/12
+f 21/43/10 13/35/10 16/38/10 22/44/10
+f 23/45/10 17/39/10 20/42/10 24/46/10
+f 24/59/13 27/60/13 25/56/13 20/55/13
+f 12/61/14 28/62/14 29/63/14 11/64/14
+f 19/58/15 26/57/15 28/62/15 12/61/15
+f 15/65/16 30/66/16 27/67/16 24/68/16
+f 22/69/17 31/70/17 32/71/17 16/72/17
+f 16/72/18 32/71/18 30/66/18 15/65/18
+f 11/64/19 29/63/19 31/70/19 22/69/19
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 3/73/20 2/74/21 33/75/21
+f 34/76/21 42/77/21 3/78/21 33/75/21
+f 35/79/21 43/80/21 42/77/21 34/76/21
+f 36/81/21 44/82/21 43/80/21 35/79/21
+f 37/83/21 45/84/21 44/82/21 36/81/21
+f 38/85/21 46/86/21 45/84/21 37/83/21
+f 39/87/21 47/88/21 46/86/21 38/85/21
+f 40/89/21 48/90/21 47/88/21 39/87/21
+f 41/91/21 49/92/21 48/90/21 40/89/21
+f 7/93/21 50/94/21 49/92/21 41/91/21
+f 50/95/21 7/96/21 8/97/22
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr0.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr0.obj
new file mode 100644
index 0000000..3c4fa17
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr0.obj
@@ -0,0 +1,148 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne4_smr0.mtl
+o Cube.001
+v 0.100000 1.200000 -0.324543
+v 0.100000 1.200000 -0.344543
+v -0.100000 1.200000 -0.344543
+v -0.100000 1.200000 -0.324543
+v 0.100000 0.700000 -0.344543
+v 0.100000 0.700000 -0.324543
+v -0.100000 0.700000 -0.344543
+v -0.100000 0.700000 -0.324543
+v 0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.334802
+v 0.000000 1.055075 -0.334802
+v 0.024805 1.055075 -0.324528
+v -0.035079 1.055075 -0.299723
+v -0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.274918
+v -0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v 0.035079 1.055075 -0.299723
+v 0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.324528
+v -0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.264644
+v 0.000000 1.055075 -0.264644
+v 0.024805 -0.499729 -0.274918
+v 0.035080 -0.499729 -0.299723
+v 0.000000 -0.499729 -0.264644
+v 0.024805 -0.499729 -0.324528
+v 0.000000 -0.499729 -0.334802
+v -0.024804 -0.499729 -0.274918
+v -0.024804 -0.499729 -0.324528
+v -0.035079 -0.499729 -0.299723
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.375000 1.000000
+vt 0.375000 0.750000
+vt 0.375000 0.500000
+vt 0.375000 0.000000
+vt 0.583333 0.000000
+vt 0.375000 0.250000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.250000 0.375000
+vt 0.250000 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.375000
+vn 0.9239 0.3827 -0.0000
+vn -0.0000 0.3826 -0.9239
+vn -0.9239 0.3827 -0.0001
+vn 0.0000 0.3827 0.9239
+vn 0.0000 -0.0000 1.0000
+vn 1.0000 -0.0000 0.0000
+vn -1.0000 0.0000 0.0000
+vn 0.7071 -0.7071 0.0000
+vn -0.7071 -0.7071 -0.0000
+vn -0.9659 0.0000 0.2588
+vn 0.9659 0.0000 0.2588
+vn -0.7814 -0.5678 0.2588
+vn 0.9659 0.0000 -0.2588
+vn -0.9659 0.0000 -0.2588
+vn 0.0000 1.0000 0.0000
+vn 0.9239 0.0000 0.3827
+vn 0.3827 -0.0000 0.9239
+vn 0.3827 0.0000 -0.9239
+vn 0.9239 0.0000 -0.3827
+vn -0.3827 -0.0000 0.9239
+vn -0.9239 -0.0000 -0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn 0.0000 0.0000 -1.0000
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 1/1/5 4/4/5 8/5/5 6/6/5
+f 5/7/6 2/2/6 1/1/6 6/6/6
+f 8/8/7 4/9/7 3/3/7 7/10/7
+f 7/11/8 5/7/9 6/6/9 8/12/8
+s 1
+f 9/13/10 10/14/5 11/15/11 12/16/12
+f 13/17/6 14/18/13 15/19/14 16/20/6
+f 17/21/13 18/22/7 19/23/7 20/24/14
+f 10/14/5 21/25/10 22/26/11 11/15/11
+f 14/18/13 23/27/5 24/28/14 15/19/14
+f 18/22/7 9/13/10 12/16/12 19/23/7
+f 21/29/15 13/30/15 14/31/15 23/32/15 17/33/15 18/34/15 9/35/15 10/36/15
+f 20/37/16 25/38/16 26/39/16 19/40/16
+f 21/25/10 13/17/6 16/20/6 22/26/11
+f 23/27/5 17/21/13 20/24/14 24/28/14
+f 24/41/17 27/42/17 25/38/17 20/37/17
+f 12/43/18 28/44/18 29/45/18 11/46/18
+f 19/40/19 26/39/19 28/44/19 12/43/19
+f 15/47/20 30/48/20 27/49/20 24/50/20
+f 22/51/21 31/52/21 32/53/21 16/54/21
+f 16/54/22 32/53/22 30/48/22 15/47/22
+f 11/46/23 29/45/23 31/52/23 22/51/23
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 7/55/24 3/56/24 2/57/24 5/58/24
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr30.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr30.obj
new file mode 100644
index 0000000..d6f8603
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr30.obj
@@ -0,0 +1,151 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne4_smr30.mtl
+o Cube.001
+v 0.234304 1.200000 -0.245825
+v 0.243228 1.200000 -0.263724
+v 0.064241 1.200000 -0.352963
+v 0.055317 1.200000 -0.335064
+v 0.243228 0.700000 -0.263724
+v 0.234304 0.700000 -0.245825
+v 0.064241 0.700000 -0.352963
+v 0.055317 0.700000 -0.335064
+v 0.167003 1.055075 -0.279363
+v 0.149388 1.055075 -0.299626
+v 0.149388 1.055075 -0.299626
+v 0.167003 1.055075 -0.279363
+v 0.102342 1.055075 -0.283885
+v 0.100469 1.055075 -0.257101
+v 0.100469 1.055075 -0.257101
+v 0.102342 1.055075 -0.283885
+v 0.144867 1.055075 -0.234966
+v 0.165129 1.055075 -0.252580
+v 0.165129 1.055075 -0.252580
+v 0.144867 1.055075 -0.234966
+v 0.122605 1.055075 -0.301499
+v 0.122605 1.055075 -0.301499
+v 0.118084 1.055075 -0.236839
+v 0.118084 1.055075 -0.236839
+v 0.144867 -0.499729 -0.234966
+v 0.165130 -0.499729 -0.252580
+v 0.118084 -0.499729 -0.236839
+v 0.167003 -0.499729 -0.279363
+v 0.149388 -0.499729 -0.299626
+v 0.100470 -0.499729 -0.257101
+v 0.122606 -0.499729 -0.301499
+v 0.102342 -0.499729 -0.283885
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.375000 1.000000
+vt 0.375000 0.750000
+vt 0.375000 0.500000
+vt 0.375000 0.000000
+vt 0.583333 0.000000
+vt 0.375000 0.250000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.250000 0.375000
+vt 0.250000 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.375000
+vn 0.8268 0.3827 0.4122
+vn 0.4122 0.3826 -0.8269
+vn -0.8268 0.3827 -0.4123
+vn -0.4122 0.3826 0.8268
+vn -0.4462 -0.0000 0.8949
+vn 0.8949 -0.0000 0.4462
+vn -0.8949 -0.0000 -0.4462
+vn 0.6328 -0.7071 0.3155
+vn -0.6328 -0.7071 -0.3155
+vn -0.9769 0.0000 0.2136
+vn 0.0000 0.0000 1.0000
+vn 0.9659 0.0000 0.2588
+vn -0.9659 0.0000 0.2588
+vn 0.9769 0.0000 -0.2136
+vn -0.7815 -0.5677 0.2588
+vn 0.9659 0.0000 -0.2588
+vn -0.9659 0.0000 -0.2588
+vn 0.0000 1.0000 -0.0000
+vn 0.6561 0.0000 0.7547
+vn -0.0698 -0.0000 0.9976
+vn 0.7547 0.0000 -0.6561
+vn 0.9976 0.0000 0.0698
+vn -0.7547 -0.0000 0.6561
+vn -0.6561 -0.0000 -0.7547
+vn -0.9976 -0.0000 -0.0698
+vn 0.0698 -0.0000 -0.9976
+vn 0.4462 0.0000 -0.8949
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 1/1/5 4/4/5 8/5/5 6/6/5
+f 5/7/6 2/2/6 1/1/6 6/6/6
+f 8/8/7 4/9/7 3/3/7 7/10/7
+f 7/11/8 5/7/9 6/6/9 8/12/8
+s 1
+f 9/13/10 10/14/11 11/15/12 12/16/10
+f 13/17/13 14/18/14 15/19/14 16/20/15
+f 17/21/16 18/22/16 19/23/17 20/24/17
+f 10/14/11 21/25/13 22/26/12 11/15/12
+f 14/18/14 23/27/11 24/28/17 15/19/14
+f 18/22/16 9/13/10 12/16/10 19/23/17
+f 21/29/18 13/30/18 14/31/18 23/32/18 17/33/18 18/34/18 9/35/18 10/36/18
+f 20/37/19 25/38/19 26/39/19 19/40/19
+f 21/25/13 13/17/13 16/20/15 22/26/12
+f 23/27/11 17/21/16 20/24/17 24/28/17
+f 24/41/20 27/42/20 25/38/20 20/37/20
+f 12/43/21 28/44/21 29/45/21 11/46/21
+f 19/40/22 26/39/22 28/44/22 12/43/22
+f 15/47/23 30/48/23 27/49/23 24/50/23
+f 22/51/24 31/52/24 32/53/24 16/54/24
+f 16/54/25 32/53/25 30/48/25 15/47/25
+f 11/46/26 29/45/26 31/52/26 22/51/26
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 7/55/27 3/56/27 2/57/27 5/58/27
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr45.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr45.obj
new file mode 100644
index 0000000..b2c828e
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr45.obj
@@ -0,0 +1,151 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne4_smr45.mtl
+o Cube.001
+v 0.300197 1.200000 -0.158776
+v 0.314339 1.200000 -0.172918
+v 0.172918 1.200000 -0.314339
+v 0.158776 1.200000 -0.300197
+v 0.314339 0.700000 -0.172918
+v 0.300197 0.700000 -0.158776
+v 0.172918 0.700000 -0.314339
+v 0.158776 0.700000 -0.300197
+v 0.247016 1.055075 -0.211936
+v 0.236741 1.055075 -0.236741
+v 0.236741 1.055075 -0.236741
+v 0.247016 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.176857 1.055075 -0.211936
+v 0.176857 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.211936 1.055075 -0.176857
+v 0.236741 1.055075 -0.187132
+v 0.236741 1.055075 -0.187132
+v 0.211936 1.055075 -0.176857
+v 0.211936 1.055075 -0.247016
+v 0.211936 1.055075 -0.247016
+v 0.187132 1.055075 -0.187132
+v 0.187132 1.055075 -0.187132
+v 0.211936 -0.499729 -0.176857
+v 0.236741 -0.499729 -0.187131
+v 0.187132 -0.499729 -0.187132
+v 0.247016 -0.499729 -0.211936
+v 0.236741 -0.499729 -0.236741
+v 0.176857 -0.499729 -0.211935
+v 0.211937 -0.499729 -0.247015
+v 0.187132 -0.499729 -0.236741
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.375000 1.000000
+vt 0.375000 0.750000
+vt 0.375000 0.500000
+vt 0.375000 0.000000
+vt 0.583333 0.000000
+vt 0.375000 0.250000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.250000 0.375000
+vt 0.250000 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.375000
+vn 0.6533 0.3827 0.6532
+vn 0.6533 0.3826 -0.6533
+vn -0.6532 0.3826 -0.6534
+vn -0.6533 0.3827 0.6533
+vn -0.7071 -0.0000 0.7071
+vn 0.7071 -0.0000 0.7071
+vn -0.7071 0.0000 -0.7071
+vn 0.5000 -0.7071 0.5000
+vn -0.5000 -0.7071 -0.5000
+vn -1.0000 0.0000 -0.0000
+vn 0.0000 0.0000 1.0000
+vn 0.9659 0.0000 0.2588
+vn -0.9659 0.0000 0.2588
+vn 1.0000 0.0000 -0.0000
+vn -0.7815 -0.5677 0.2588
+vn 0.9659 0.0000 -0.2588
+vn -0.9659 0.0000 -0.2588
+vn 0.0000 1.0000 -0.0000
+vn 0.3827 0.0000 0.9239
+vn -0.3827 -0.0000 0.9239
+vn 0.9239 0.0000 -0.3827
+vn 0.9239 0.0000 0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn -0.9239 -0.0000 -0.3827
+vn 0.3827 -0.0000 -0.9239
+vn 0.7071 0.0000 -0.7071
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 1/1/5 4/4/5 8/5/5 6/6/5
+f 5/7/6 2/2/6 1/1/6 6/6/6
+f 8/8/7 4/9/7 3/3/7 7/10/7
+f 7/11/8 5/7/9 6/6/9 8/12/8
+s 1
+f 9/13/10 10/14/11 11/15/12 12/16/10
+f 13/17/13 14/18/14 15/19/14 16/20/15
+f 17/21/16 18/22/16 19/23/17 20/24/17
+f 10/14/11 21/25/13 22/26/12 11/15/12
+f 14/18/14 23/27/11 24/28/17 15/19/14
+f 18/22/16 9/13/10 12/16/10 19/23/17
+f 21/29/18 13/30/18 14/31/18 23/32/18 17/33/18 18/34/18 9/35/18 10/36/18
+f 20/37/19 25/38/19 26/39/19 19/40/19
+f 21/25/13 13/17/13 16/20/15 22/26/12
+f 23/27/11 17/21/16 20/24/17 24/28/17
+f 24/41/20 27/42/20 25/38/20 20/37/20
+f 12/43/21 28/44/21 29/45/21 11/46/21
+f 19/40/22 26/39/22 28/44/22 12/43/22
+f 15/47/23 30/48/23 27/49/23 24/50/23
+f 22/51/24 31/52/24 32/53/24 16/54/24
+f 16/54/25 32/53/25 30/48/25 15/47/25
+f 11/46/26 29/45/26 31/52/26 22/51/26
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 7/55/27 3/56/27 2/57/27 5/58/27
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr60.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr60.obj
new file mode 100644
index 0000000..c49488b
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_ne4_smr60.obj
@@ -0,0 +1,151 @@
+# Blender v3.0.0 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_ne4_smr60.mtl
+o Cube.001
+v 0.335064 1.200000 -0.055317
+v 0.352963 1.200000 -0.064241
+v 0.263724 1.200000 -0.243228
+v 0.245825 1.200000 -0.234304
+v 0.352963 0.700000 -0.064241
+v 0.335064 0.700000 -0.055317
+v 0.263724 0.700000 -0.243228
+v 0.245825 0.700000 -0.234304
+v 0.301499 1.055075 -0.122605
+v 0.299626 1.055075 -0.149388
+v 0.299626 1.055075 -0.149388
+v 0.301499 1.055075 -0.122605
+v 0.252580 1.055075 -0.165129
+v 0.234966 1.055075 -0.144867
+v 0.234966 1.055075 -0.144867
+v 0.252580 1.055075 -0.165129
+v 0.257101 1.055075 -0.100469
+v 0.283885 1.055075 -0.102342
+v 0.283885 1.055075 -0.102342
+v 0.257101 1.055075 -0.100469
+v 0.279363 1.055075 -0.167002
+v 0.279363 1.055075 -0.167002
+v 0.236839 1.055075 -0.118084
+v 0.236839 1.055075 -0.118084
+v 0.257102 -0.499729 -0.100469
+v 0.283885 -0.499729 -0.102341
+v 0.236839 -0.499729 -0.118084
+v 0.301499 -0.499729 -0.122605
+v 0.299626 -0.499729 -0.149388
+v 0.234966 -0.499729 -0.144866
+v 0.279364 -0.499729 -0.167002
+v 0.252580 -0.499729 -0.165129
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.375000 1.000000
+vt 0.375000 0.750000
+vt 0.375000 0.500000
+vt 0.375000 0.000000
+vt 0.583333 0.000000
+vt 0.375000 0.250000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.250000 0.375000
+vt 0.250000 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.375000
+vn 0.4123 0.3827 0.8268
+vn 0.8268 0.3826 -0.4123
+vn -0.4122 0.3827 -0.8269
+vn -0.8268 0.3827 0.4123
+vn -0.8949 -0.0000 0.4462
+vn 0.4462 0.0000 0.8949
+vn -0.4462 0.0000 -0.8949
+vn 0.3155 -0.7071 0.6328
+vn -0.3155 -0.7071 -0.6328
+vn -0.9769 0.0000 -0.2136
+vn 0.0000 0.0000 1.0000
+vn 0.9659 0.0000 0.2588
+vn -0.9659 0.0000 0.2588
+vn 0.9769 0.0000 0.2136
+vn -0.7817 -0.5674 0.2588
+vn 0.9659 0.0000 -0.2588
+vn -0.9659 0.0000 -0.2588
+vn 0.0000 1.0000 0.0000
+vn 0.0698 0.0000 0.9976
+vn -0.6561 -0.0000 0.7547
+vn 0.9976 0.0000 -0.0698
+vn 0.7547 0.0000 0.6561
+vn -0.9976 -0.0000 0.0698
+vn -0.0698 -0.0000 -0.9976
+vn -0.7547 -0.0000 -0.6561
+vn 0.6561 -0.0000 -0.7547
+vn 0.8949 0.0000 -0.4462
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4
+f 1/1/5 4/4/5 8/5/5 6/6/5
+f 5/7/6 2/2/6 1/1/6 6/6/6
+f 8/8/7 4/9/7 3/3/7 7/10/7
+f 7/11/8 5/7/9 6/6/9 8/12/8
+s 1
+f 9/13/10 10/14/11 11/15/12 12/16/10
+f 13/17/13 14/18/14 15/19/14 16/20/15
+f 17/21/16 18/22/16 19/23/17 20/24/17
+f 10/14/11 21/25/13 22/26/12 11/15/12
+f 14/18/14 23/27/11 24/28/17 15/19/14
+f 18/22/16 9/13/10 12/16/10 19/23/17
+f 21/29/18 13/30/18 14/31/18 23/32/18 17/33/18 18/34/18 9/35/18 10/36/18
+f 20/37/19 25/38/19 26/39/19 19/40/19
+f 21/25/13 13/17/13 16/20/15 22/26/12
+f 23/27/11 17/21/16 20/24/17 24/28/17
+f 24/41/20 27/42/20 25/38/20 20/37/20
+f 12/43/21 28/44/21 29/45/21 11/46/21
+f 19/40/22 26/39/22 28/44/22 12/43/22
+f 15/47/23 30/48/23 27/49/23 24/50/23
+f 22/51/24 31/52/24 32/53/24 16/54/24
+f 16/54/25 32/53/25 30/48/25 15/47/25
+f 11/46/26 29/45/26 31/52/26 22/51/26
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 7/55/27 3/56/27 2/57/27 5/58/27
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr0.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr0.obj
new file mode 100644
index 0000000..a733a2f
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr0.obj
@@ -0,0 +1,227 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs10_smr0.mtl
+o Cube.001
+v 0.000000 1.300000 -0.324543
+v 0.100000 1.200000 -0.324543
+v 0.100000 1.200000 -0.344543
+v 0.000000 1.300000 -0.344543
+v -0.100000 1.200000 -0.344543
+v -0.100000 1.200000 -0.324543
+v 0.000000 0.800000 -0.344543
+v 0.100000 0.700000 -0.344543
+v 0.100000 0.700000 -0.324543
+v 0.000000 0.800000 -0.324543
+v -0.100000 0.700000 -0.344543
+v -0.100000 0.700000 -0.324543
+v 0.100000 0.800000 -0.324543
+v 0.000000 0.900000 -0.324543
+v 0.100000 0.900000 -0.324543
+v 0.000000 1.000000 -0.324543
+v 0.100000 1.000000 -0.324543
+v 0.000000 1.100000 -0.324543
+v 0.100000 1.100000 -0.324543
+v 0.000000 1.200000 -0.324543
+v -0.100000 0.800000 -0.324543
+v -0.100000 0.900000 -0.324543
+v -0.100000 1.000000 -0.324543
+v -0.100000 1.100000 -0.324543
+v 0.100000 0.800000 -0.344543
+v 0.100000 0.900000 -0.344543
+v 0.100000 1.000000 -0.344543
+v 0.100000 1.100000 -0.344543
+v -0.100000 0.800000 -0.344543
+v -0.100000 0.900000 -0.344543
+v -0.100000 1.000000 -0.344543
+v -0.100000 1.100000 -0.344543
+v 0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.334802
+v 0.000000 1.055075 -0.334802
+v 0.024805 1.055075 -0.324528
+v -0.035079 1.055075 -0.299723
+v -0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.274918
+v -0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v 0.035079 1.055075 -0.299723
+v 0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.324528
+v -0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.264644
+v 0.000000 1.055075 -0.264644
+v 0.024805 -0.499729 -0.274918
+v 0.035080 -0.499729 -0.299723
+v 0.000000 -0.499729 -0.264644
+v 0.024805 -0.499729 -0.324528
+v 0.000000 -0.499729 -0.334802
+v -0.024804 -0.499729 -0.274918
+v -0.024804 -0.499729 -0.324528
+v -0.035079 -0.499729 -0.299723
+vt 0.583333 0.875000
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.375000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.250000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.250000 0.750000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.416667 0.750000
+vt 0.416667 0.875000
+vt 0.375000 0.875000
+vt 0.458333 0.750000
+vt 0.458333 0.875000
+vt 0.500000 0.750000
+vt 0.500000 0.875000
+vt 0.541667 0.750000
+vt 0.541667 0.875000
+vt 0.416667 1.000000
+vt 0.375000 1.000000
+vt 0.458333 1.000000
+vt 0.500000 1.000000
+vt 0.541667 1.000000
+vt 0.416667 0.500000
+vt 0.458333 0.500000
+vt 0.500000 0.500000
+vt 0.541667 0.500000
+vt 0.375000 0.000000
+vt 0.416667 0.000000
+vt 0.416667 0.250000
+vt 0.375000 0.250000
+vt 0.458333 0.000000
+vt 0.458333 0.250000
+vt 0.500000 0.000000
+vt 0.500000 0.250000
+vt 0.541667 0.000000
+vt 0.541667 0.250000
+vt 0.583333 0.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.125000 1.000000
+vt 0.000000 1.000000
+vt -0.000000 0.875000
+vt 0.000000 0.750000
+vt 0.000000 0.625000
+vt 0.000000 0.500000
+vt 0.000000 0.375000
+vt 0.125000 0.375000
+vt 0.250000 0.875000
+vt 0.250000 1.000000
+vt 0.250000 0.375000
+vt 0.250000 0.500000
+vt 0.250000 0.625000
+vt 0.250000 0.750000
+vn 0.0001 -0.7071 0.7071
+vn 0.9239 0.3827 -0.0000
+vn -0.0000 0.3827 -0.9239
+vn 0.0002 -0.7071 -0.7071
+vn -0.9239 0.3827 0.0000
+vn 0.0000 0.3827 0.9239
+vn -0.7071 -0.7071 0.0000
+vn 0.7071 -0.7071 0.0000
+vn 0.0000 0.0000 1.0000
+vn 1.0000 0.0000 0.0000
+vn -1.0000 0.0000 0.0000
+vn 0.0000 1.0000 0.0000
+vn 0.9239 0.0000 0.3827
+vn 0.3827 -0.0000 0.9239
+vn 0.3827 0.0000 -0.9239
+vn 0.9239 0.0000 -0.3827
+vn -0.3827 -0.0000 0.9239
+vn -0.9239 -0.0000 -0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn 0.0000 0.0000 -1.0000
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4 5/5/5 6/6/6
+f 7/7/7 8/8/7 9/9/7 10/10/7
+f 11/11/8 7/7/8 10/10/8 12/12/8
+f 9/9/9 13/13/9 14/14/9 10/15/9
+f 13/13/9 15/16/9 16/17/9 14/14/9
+f 15/16/9 17/18/9 18/19/9 16/17/9
+f 17/18/9 19/20/9 20/21/9 18/19/9
+f 19/20/9 2/2/9 1/1/9 20/21/9
+f 10/15/9 14/14/9 21/22/9 12/23/9
+f 14/14/9 16/17/9 22/24/9 21/22/9
+f 16/17/9 18/19/9 23/25/9 22/24/9
+f 18/19/9 20/21/9 24/26/9 23/25/9
+f 20/21/9 1/1/9 6/6/9 24/26/9
+f 8/8/10 25/27/10 13/13/10 9/9/10
+f 25/27/10 26/28/10 15/16/10 13/13/10
+f 26/28/10 27/29/10 17/18/10 15/16/10
+f 27/29/10 28/30/10 19/20/10 17/18/10
+f 28/30/10 3/3/10 2/2/10 19/20/10
+f 12/31/11 21/32/11 29/33/11 11/34/11
+f 21/32/11 22/35/11 30/36/11 29/33/11
+f 22/35/11 23/37/11 31/38/11 30/36/11
+f 23/37/11 24/39/11 32/40/11 31/38/11
+f 24/39/11 6/41/11 5/5/11 32/40/11
+s 1
+f 33/42/9 34/43/9 35/44/9 36/45/9
+f 37/46/9 38/47/9 39/48/9 40/49/9
+f 41/50/9 42/51/9 43/52/9 44/53/9
+f 34/43/9 45/54/9 46/55/9 35/44/9
+f 38/47/9 47/56/9 48/57/9 39/48/9
+f 42/51/9 33/42/9 36/45/9 43/52/9
+f 45/58/12 37/59/12 38/60/12 47/61/12 41/62/12 42/63/12 33/64/12 34/65/12
+f 44/66/13 49/67/13 50/68/13 43/69/13
+f 45/54/9 37/46/9 40/49/9 46/55/9
+f 47/56/9 41/50/9 44/53/9 48/57/9
+f 48/70/14 51/71/14 49/67/14 44/66/14
+f 36/72/15 52/73/15 53/74/15 35/75/15
+f 43/69/16 50/68/16 52/73/16 36/72/16
+f 39/76/17 54/77/17 51/78/17 48/79/17
+f 46/80/18 55/81/18 56/82/18 40/83/18
+f 40/83/19 56/82/19 54/77/19 39/76/19
+f 35/75/20 53/74/20 55/81/20 46/80/20
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 4/84/21 3/85/21 28/86/21 27/87/21 26/88/21 25/89/21 8/90/21 7/91/21
+f 32/92/21 5/93/21 4/84/21 7/91/21 11/94/21 29/95/21 30/96/21 31/97/21
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr30.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr30.obj
new file mode 100644
index 0000000..8c2557c
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr30.obj
@@ -0,0 +1,228 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs10_smr30.mtl
+o Cube.001
+v 0.144810 1.300000 -0.290445
+v 0.234304 1.200000 -0.245825
+v 0.243228 1.200000 -0.263724
+v 0.153734 1.300000 -0.308343
+v 0.064241 1.200000 -0.352963
+v 0.055317 1.200000 -0.335064
+v 0.153734 0.800000 -0.308343
+v 0.243228 0.700000 -0.263724
+v 0.234304 0.700000 -0.245825
+v 0.144810 0.800000 -0.290445
+v 0.064241 0.700000 -0.352963
+v 0.055317 0.700000 -0.335064
+v 0.234304 0.800000 -0.245825
+v 0.144810 0.900000 -0.290445
+v 0.234304 0.900000 -0.245825
+v 0.144810 1.000000 -0.290445
+v 0.234304 1.000000 -0.245825
+v 0.144810 1.100000 -0.290445
+v 0.234304 1.100000 -0.245825
+v 0.144810 1.200000 -0.290445
+v 0.055317 0.800000 -0.335064
+v 0.055317 0.900000 -0.335064
+v 0.055317 1.000000 -0.335064
+v 0.055317 1.100000 -0.335064
+v 0.243228 0.800000 -0.263724
+v 0.243228 0.900000 -0.263724
+v 0.243228 1.000000 -0.263724
+v 0.243228 1.100000 -0.263724
+v 0.064241 0.800000 -0.352963
+v 0.064241 0.900000 -0.352963
+v 0.064241 1.000000 -0.352963
+v 0.064241 1.100000 -0.352963
+v 0.167003 1.055075 -0.279363
+v 0.149388 1.055075 -0.299626
+v 0.149388 1.055075 -0.299626
+v 0.167003 1.055075 -0.279363
+v 0.102342 1.055075 -0.283885
+v 0.100469 1.055075 -0.257101
+v 0.100469 1.055075 -0.257101
+v 0.102342 1.055075 -0.283885
+v 0.144867 1.055075 -0.234966
+v 0.165129 1.055075 -0.252580
+v 0.165129 1.055075 -0.252580
+v 0.144867 1.055075 -0.234966
+v 0.122605 1.055075 -0.301499
+v 0.122605 1.055075 -0.301499
+v 0.118084 1.055075 -0.236839
+v 0.118084 1.055075 -0.236839
+v 0.144867 -0.499729 -0.234966
+v 0.165130 -0.499729 -0.252580
+v 0.118084 -0.499729 -0.236839
+v 0.167003 -0.499729 -0.279363
+v 0.149388 -0.499729 -0.299626
+v 0.100470 -0.499729 -0.257101
+v 0.122606 -0.499729 -0.301499
+v 0.102342 -0.499729 -0.283885
+vt 0.583333 0.875000
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.375000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.250000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.250000 0.750000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.416667 0.750000
+vt 0.416667 0.875000
+vt 0.375000 0.875000
+vt 0.458333 0.750000
+vt 0.458333 0.875000
+vt 0.500000 0.750000
+vt 0.500000 0.875000
+vt 0.541667 0.750000
+vt 0.541667 0.875000
+vt 0.416667 1.000000
+vt 0.375000 1.000000
+vt 0.458333 1.000000
+vt 0.500000 1.000000
+vt 0.541667 1.000000
+vt 0.416667 0.500000
+vt 0.458333 0.500000
+vt 0.500000 0.500000
+vt 0.541667 0.500000
+vt 0.375000 0.000000
+vt 0.416667 0.000000
+vt 0.416667 0.250000
+vt 0.375000 0.250000
+vt 0.458333 0.000000
+vt 0.458333 0.250000
+vt 0.500000 0.000000
+vt 0.500000 0.250000
+vt 0.541667 0.000000
+vt 0.541667 0.250000
+vt 0.583333 0.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.125000 1.000000
+vt 0.000000 1.000000
+vt -0.000000 0.875000
+vt 0.000000 0.750000
+vt 0.000000 0.625000
+vt 0.000000 0.500000
+vt 0.000000 0.375000
+vt 0.125000 0.375000
+vt 0.250000 0.875000
+vt 0.250000 1.000000
+vt 0.250000 0.375000
+vt 0.250000 0.500000
+vt 0.250000 0.625000
+vt 0.250000 0.750000
+vn -0.3152 -0.7071 0.6329
+vn 0.8268 0.3827 0.4122
+vn 0.4122 0.3827 -0.8268
+vn 0.3156 -0.7071 -0.6327
+vn -0.8268 0.3827 -0.4122
+vn -0.4122 0.3827 0.8268
+vn -0.6328 -0.7071 -0.3155
+vn 0.6328 -0.7071 0.3155
+vn -0.4462 -0.0000 0.8949
+vn 0.8949 -0.0000 0.4462
+vn -0.8949 0.0000 -0.4462
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.6561 0.0000 0.7547
+vn -0.0698 -0.0000 0.9976
+vn 0.7547 0.0000 -0.6561
+vn 0.9976 0.0000 0.0698
+vn -0.7547 -0.0000 0.6561
+vn -0.6561 -0.0000 -0.7547
+vn -0.9976 -0.0000 -0.0698
+vn 0.0698 -0.0000 -0.9976
+vn 0.4462 0.0000 -0.8949
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4 5/5/5 6/6/6
+f 7/7/7 8/8/7 9/9/7 10/10/7
+f 11/11/8 7/7/8 10/10/8 12/12/8
+f 9/9/9 13/13/9 14/14/9 10/15/9
+f 13/13/9 15/16/9 16/17/9 14/14/9
+f 15/16/9 17/18/9 18/19/9 16/17/9
+f 17/18/9 19/20/9 20/21/9 18/19/9
+f 19/20/9 2/2/9 1/1/9 20/21/9
+f 10/15/9 14/14/9 21/22/9 12/23/9
+f 14/14/9 16/17/9 22/24/9 21/22/9
+f 16/17/9 18/19/9 23/25/9 22/24/9
+f 18/19/9 20/21/9 24/26/9 23/25/9
+f 20/21/9 1/1/9 6/6/9 24/26/9
+f 8/8/10 25/27/10 13/13/10 9/9/10
+f 25/27/10 26/28/10 15/16/10 13/13/10
+f 26/28/10 27/29/10 17/18/10 15/16/10
+f 27/29/10 28/30/10 19/20/10 17/18/10
+f 28/30/10 3/3/10 2/2/10 19/20/10
+f 12/31/11 21/32/11 29/33/11 11/34/11
+f 21/32/11 22/35/11 30/36/11 29/33/11
+f 22/35/11 23/37/11 31/38/11 30/36/11
+f 23/37/11 24/39/11 32/40/11 31/38/11
+f 24/39/11 6/41/11 5/5/11 32/40/11
+s 1
+f 33/42/12 34/43/12 35/44/12 36/45/12
+f 37/46/12 38/47/12 39/48/12 40/49/12
+f 41/50/12 42/51/12 43/52/12 44/53/12
+f 34/43/12 45/54/12 46/55/12 35/44/12
+f 38/47/12 47/56/12 48/57/12 39/48/12
+f 42/51/12 33/42/12 36/45/12 43/52/12
+f 45/58/13 37/59/13 38/60/13 47/61/13 41/62/13 42/63/13 33/64/13 34/65/13
+f 44/66/14 49/67/14 50/68/14 43/69/14
+f 45/54/12 37/46/12 40/49/12 46/55/12
+f 47/56/12 41/50/12 44/53/12 48/57/12
+f 48/70/15 51/71/15 49/67/15 44/66/15
+f 36/72/16 52/73/16 53/74/16 35/75/16
+f 43/69/17 50/68/17 52/73/17 36/72/17
+f 39/76/18 54/77/18 51/78/18 48/79/18
+f 46/80/19 55/81/19 56/82/19 40/83/19
+f 40/83/20 56/82/20 54/77/20 39/76/20
+f 35/75/21 53/74/21 55/81/21 46/80/21
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 4/84/22 3/85/22 28/86/22 27/87/22 26/88/22 25/89/22 8/90/22 7/91/22
+f 32/92/22 5/93/22 4/84/22 7/91/22 11/94/22 29/95/22 30/96/22 31/97/22
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr45.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr45.obj
new file mode 100644
index 0000000..6343595
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr45.obj
@@ -0,0 +1,228 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs10_smr45.mtl
+o Cube.001
+v 0.229487 1.300000 -0.229487
+v 0.300197 1.200000 -0.158776
+v 0.314339 1.200000 -0.172918
+v 0.243629 1.300000 -0.243629
+v 0.172918 1.200000 -0.314339
+v 0.158776 1.200000 -0.300197
+v 0.243629 0.800000 -0.243629
+v 0.314339 0.700000 -0.172918
+v 0.300197 0.700000 -0.158776
+v 0.229487 0.800000 -0.229487
+v 0.172918 0.700000 -0.314339
+v 0.158776 0.700000 -0.300197
+v 0.300197 0.800000 -0.158776
+v 0.229487 0.900000 -0.229487
+v 0.300197 0.900000 -0.158776
+v 0.229487 1.000000 -0.229487
+v 0.300197 1.000000 -0.158776
+v 0.229487 1.100000 -0.229487
+v 0.300197 1.100000 -0.158776
+v 0.229487 1.200000 -0.229487
+v 0.158776 0.800000 -0.300197
+v 0.158776 0.900000 -0.300197
+v 0.158776 1.000000 -0.300197
+v 0.158776 1.100000 -0.300197
+v 0.314339 0.800000 -0.172918
+v 0.314339 0.900000 -0.172918
+v 0.314339 1.000000 -0.172918
+v 0.314339 1.100000 -0.172918
+v 0.172918 0.800000 -0.314339
+v 0.172918 0.900000 -0.314339
+v 0.172918 1.000000 -0.314339
+v 0.172918 1.100000 -0.314339
+v 0.247016 1.055075 -0.211936
+v 0.236741 1.055075 -0.236741
+v 0.236741 1.055075 -0.236741
+v 0.247016 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.176857 1.055075 -0.211936
+v 0.176857 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.211936 1.055075 -0.176857
+v 0.236741 1.055075 -0.187132
+v 0.236741 1.055075 -0.187132
+v 0.211936 1.055075 -0.176857
+v 0.211936 1.055075 -0.247016
+v 0.211936 1.055075 -0.247016
+v 0.187132 1.055075 -0.187132
+v 0.187132 1.055075 -0.187132
+v 0.211936 -0.499729 -0.176857
+v 0.236741 -0.499729 -0.187131
+v 0.187132 -0.499729 -0.187132
+v 0.247016 -0.499729 -0.211936
+v 0.236741 -0.499729 -0.236741
+v 0.176857 -0.499729 -0.211935
+v 0.211937 -0.499729 -0.247015
+v 0.187132 -0.499729 -0.236741
+vt 0.583333 0.875000
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.375000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.250000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.250000 0.750000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.416667 0.750000
+vt 0.416667 0.875000
+vt 0.375000 0.875000
+vt 0.458333 0.750000
+vt 0.458333 0.875000
+vt 0.500000 0.750000
+vt 0.500000 0.875000
+vt 0.541667 0.750000
+vt 0.541667 0.875000
+vt 0.416667 1.000000
+vt 0.375000 1.000000
+vt 0.458333 1.000000
+vt 0.500000 1.000000
+vt 0.541667 1.000000
+vt 0.416667 0.500000
+vt 0.458333 0.500000
+vt 0.500000 0.500000
+vt 0.541667 0.500000
+vt 0.375000 0.000000
+vt 0.416667 0.000000
+vt 0.416667 0.250000
+vt 0.375000 0.250000
+vt 0.458333 0.000000
+vt 0.458333 0.250000
+vt 0.500000 0.000000
+vt 0.500000 0.250000
+vt 0.541667 0.000000
+vt 0.541667 0.250000
+vt 0.583333 0.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.125000 1.000000
+vt 0.000000 1.000000
+vt -0.000000 0.875000
+vt 0.000000 0.750000
+vt 0.000000 0.625000
+vt 0.000000 0.500000
+vt 0.000000 0.375000
+vt 0.125000 0.375000
+vt 0.250000 0.875000
+vt 0.250000 1.000000
+vt 0.250000 0.375000
+vt 0.250000 0.500000
+vt 0.250000 0.625000
+vt 0.250000 0.750000
+vn -0.4998 -0.7071 0.5002
+vn 0.6533 0.3827 0.6533
+vn 0.6533 0.3827 -0.6533
+vn 0.5001 -0.7071 -0.4999
+vn -0.6533 0.3827 -0.6532
+vn -0.6533 0.3827 0.6533
+vn -0.5000 -0.7071 -0.5000
+vn 0.5000 -0.7071 0.5000
+vn -0.7071 0.0000 0.7071
+vn 0.7071 0.0000 0.7071
+vn -0.7071 0.0000 -0.7071
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.3827 0.0000 0.9239
+vn -0.3827 -0.0000 0.9239
+vn 0.9239 0.0000 -0.3827
+vn 0.9239 0.0000 0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn -0.9239 -0.0000 -0.3827
+vn 0.3827 -0.0000 -0.9239
+vn 0.7071 0.0000 -0.7071
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4 5/5/5 6/6/6
+f 7/7/7 8/8/7 9/9/7 10/10/7
+f 11/11/8 7/7/8 10/10/8 12/12/8
+f 9/9/9 13/13/9 14/14/9 10/15/9
+f 13/13/9 15/16/9 16/17/9 14/14/9
+f 15/16/9 17/18/9 18/19/9 16/17/9
+f 17/18/9 19/20/9 20/21/9 18/19/9
+f 19/20/9 2/2/9 1/1/9 20/21/9
+f 10/15/9 14/14/9 21/22/9 12/23/9
+f 14/14/9 16/17/9 22/24/9 21/22/9
+f 16/17/9 18/19/9 23/25/9 22/24/9
+f 18/19/9 20/21/9 24/26/9 23/25/9
+f 20/21/9 1/1/9 6/6/9 24/26/9
+f 8/8/10 25/27/10 13/13/10 9/9/10
+f 25/27/10 26/28/10 15/16/10 13/13/10
+f 26/28/10 27/29/10 17/18/10 15/16/10
+f 27/29/10 28/30/10 19/20/10 17/18/10
+f 28/30/10 3/3/10 2/2/10 19/20/10
+f 12/31/11 21/32/11 29/33/11 11/34/11
+f 21/32/11 22/35/11 30/36/11 29/33/11
+f 22/35/11 23/37/11 31/38/11 30/36/11
+f 23/37/11 24/39/11 32/40/11 31/38/11
+f 24/39/11 6/41/11 5/5/11 32/40/11
+s 1
+f 33/42/12 34/43/12 35/44/12 36/45/12
+f 37/46/12 38/47/12 39/48/12 40/49/12
+f 41/50/12 42/51/12 43/52/12 44/53/12
+f 34/43/12 45/54/12 46/55/12 35/44/12
+f 38/47/12 47/56/12 48/57/12 39/48/12
+f 42/51/12 33/42/12 36/45/12 43/52/12
+f 45/58/13 37/59/13 38/60/13 47/61/13 41/62/13 42/63/13 33/64/13 34/65/13
+f 44/66/14 49/67/14 50/68/14 43/69/14
+f 45/54/12 37/46/12 40/49/12 46/55/12
+f 47/56/12 41/50/12 44/53/12 48/57/12
+f 48/70/15 51/71/15 49/67/15 44/66/15
+f 36/72/16 52/73/16 53/74/16 35/75/16
+f 43/69/17 50/68/17 52/73/17 36/72/17
+f 39/76/18 54/77/18 51/78/18 48/79/18
+f 46/80/19 55/81/19 56/82/19 40/83/19
+f 40/83/20 56/82/20 54/77/20 39/76/20
+f 35/75/21 53/74/21 55/81/21 46/80/21
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 4/84/22 3/85/22 28/86/22 27/87/22 26/88/22 25/89/22 8/90/22 7/91/22
+f 32/92/22 5/93/22 4/84/22 7/91/22 11/94/22 29/95/22 30/96/22 31/97/22
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr60.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr60.obj
new file mode 100644
index 0000000..94aa189
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs10_smr60.obj
@@ -0,0 +1,228 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs10_smr60.mtl
+o Cube.001
+v 0.290445 1.300000 -0.144810
+v 0.335064 1.200000 -0.055317
+v 0.352963 1.200000 -0.064241
+v 0.308343 1.300000 -0.153734
+v 0.263724 1.200000 -0.243228
+v 0.245825 1.200000 -0.234304
+v 0.308343 0.800000 -0.153734
+v 0.352963 0.700000 -0.064241
+v 0.335064 0.700000 -0.055317
+v 0.290445 0.800000 -0.144810
+v 0.263724 0.700000 -0.243228
+v 0.245825 0.700000 -0.234304
+v 0.335064 0.800000 -0.055317
+v 0.290445 0.900000 -0.144810
+v 0.335064 0.900000 -0.055317
+v 0.290445 1.000000 -0.144810
+v 0.335064 1.000000 -0.055317
+v 0.290445 1.100000 -0.144810
+v 0.335064 1.100000 -0.055317
+v 0.290445 1.200000 -0.144810
+v 0.245825 0.800000 -0.234304
+v 0.245825 0.900000 -0.234304
+v 0.245825 1.000000 -0.234304
+v 0.245825 1.100000 -0.234304
+v 0.352963 0.800000 -0.064241
+v 0.352963 0.900000 -0.064241
+v 0.352963 1.000000 -0.064241
+v 0.352963 1.100000 -0.064241
+v 0.263724 0.800000 -0.243228
+v 0.263724 0.900000 -0.243228
+v 0.263724 1.000000 -0.243228
+v 0.263724 1.100000 -0.243228
+v 0.301499 1.055075 -0.122605
+v 0.299626 1.055075 -0.149388
+v 0.299626 1.055075 -0.149388
+v 0.301499 1.055075 -0.122605
+v 0.252580 1.055075 -0.165129
+v 0.234966 1.055075 -0.144867
+v 0.234966 1.055075 -0.144867
+v 0.252580 1.055075 -0.165129
+v 0.257101 1.055075 -0.100469
+v 0.283885 1.055075 -0.102342
+v 0.283885 1.055075 -0.102342
+v 0.257101 1.055075 -0.100469
+v 0.279363 1.055075 -0.167002
+v 0.279363 1.055075 -0.167002
+v 0.236839 1.055075 -0.118084
+v 0.236839 1.055075 -0.118084
+v 0.257102 -0.499729 -0.100469
+v 0.283885 -0.499729 -0.102341
+v 0.236839 -0.499729 -0.118084
+v 0.301499 -0.499729 -0.122605
+v 0.299626 -0.499729 -0.149388
+v 0.234966 -0.499729 -0.144866
+v 0.279364 -0.499729 -0.167002
+v 0.252580 -0.499729 -0.165129
+vt 0.583333 0.875000
+vt 0.583333 0.750000
+vt 0.583333 0.500000
+vt 0.583333 0.375000
+vt 0.583333 0.250000
+vt 0.583333 1.000000
+vt 0.250000 0.500000
+vt 0.375000 0.500000
+vt 0.375000 0.750000
+vt 0.250000 0.750000
+vt 0.125000 0.500000
+vt 0.125000 0.750000
+vt 0.416667 0.750000
+vt 0.416667 0.875000
+vt 0.375000 0.875000
+vt 0.458333 0.750000
+vt 0.458333 0.875000
+vt 0.500000 0.750000
+vt 0.500000 0.875000
+vt 0.541667 0.750000
+vt 0.541667 0.875000
+vt 0.416667 1.000000
+vt 0.375000 1.000000
+vt 0.458333 1.000000
+vt 0.500000 1.000000
+vt 0.541667 1.000000
+vt 0.416667 0.500000
+vt 0.458333 0.500000
+vt 0.500000 0.500000
+vt 0.541667 0.500000
+vt 0.375000 0.000000
+vt 0.416667 0.000000
+vt 0.416667 0.250000
+vt 0.375000 0.250000
+vt 0.458333 0.000000
+vt 0.458333 0.250000
+vt 0.500000 0.000000
+vt 0.500000 0.250000
+vt 0.541667 0.000000
+vt 0.541667 0.250000
+vt 0.583333 0.000000
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.125000 1.000000
+vt 0.000000 1.000000
+vt -0.000000 0.875000
+vt 0.000000 0.750000
+vt 0.000000 0.625000
+vt 0.000000 0.500000
+vt 0.000000 0.375000
+vt 0.125000 0.375000
+vt 0.250000 0.875000
+vt 0.250000 1.000000
+vt 0.250000 0.375000
+vt 0.250000 0.500000
+vt 0.250000 0.625000
+vt 0.250000 0.750000
+vn -0.6326 -0.7071 0.3159
+vn 0.4123 0.3827 0.8268
+vn 0.8268 0.3827 -0.4123
+vn 0.6328 -0.7071 -0.3155
+vn -0.4123 0.3827 -0.8268
+vn -0.8268 0.3827 0.4123
+vn -0.3155 -0.7071 -0.6328
+vn 0.3155 -0.7071 0.6328
+vn -0.8949 0.0000 0.4462
+vn 0.4462 0.0000 0.8949
+vn -0.4462 0.0000 -0.8949
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 0.0000
+vn 0.0698 0.0000 0.9976
+vn -0.6561 -0.0000 0.7547
+vn 0.9976 0.0000 -0.0698
+vn 0.7547 0.0000 0.6561
+vn -0.9976 -0.0000 0.0698
+vn -0.0698 -0.0000 -0.9976
+vn -0.7547 -0.0000 -0.6561
+vn 0.6561 -0.0000 -0.7547
+vn 0.8949 0.0000 -0.4462
+g Cube.001_Cube.001_Default_OBJ
+usemtl Default_OBJ
+s off
+f 1/1/1 2/2/2 3/3/3 4/4/4 5/5/5 6/6/6
+f 7/7/7 8/8/7 9/9/7 10/10/7
+f 11/11/8 7/7/8 10/10/8 12/12/8
+f 9/9/9 13/13/9 14/14/9 10/15/9
+f 13/13/9 15/16/9 16/17/9 14/14/9
+f 15/16/9 17/18/9 18/19/9 16/17/9
+f 17/18/9 19/20/9 20/21/9 18/19/9
+f 19/20/9 2/2/9 1/1/9 20/21/9
+f 10/15/9 14/14/9 21/22/9 12/23/9
+f 14/14/9 16/17/9 22/24/9 21/22/9
+f 16/17/9 18/19/9 23/25/9 22/24/9
+f 18/19/9 20/21/9 24/26/9 23/25/9
+f 20/21/9 1/1/9 6/6/9 24/26/9
+f 8/8/10 25/27/10 13/13/10 9/9/10
+f 25/27/10 26/28/10 15/16/10 13/13/10
+f 26/28/10 27/29/10 17/18/10 15/16/10
+f 27/29/10 28/30/10 19/20/10 17/18/10
+f 28/30/10 3/3/10 2/2/10 19/20/10
+f 12/31/11 21/32/11 29/33/11 11/34/11
+f 21/32/11 22/35/11 30/36/11 29/33/11
+f 22/35/11 23/37/11 31/38/11 30/36/11
+f 23/37/11 24/39/11 32/40/11 31/38/11
+f 24/39/11 6/41/11 5/5/11 32/40/11
+s 1
+f 33/42/12 34/43/12 35/44/12 36/45/12
+f 37/46/12 38/47/12 39/48/12 40/49/12
+f 41/50/12 42/51/12 43/52/12 44/53/12
+f 34/43/12 45/54/12 46/55/12 35/44/12
+f 38/47/12 47/56/12 48/57/12 39/48/12
+f 42/51/12 33/42/12 36/45/12 43/52/12
+f 45/58/13 37/59/13 38/60/13 47/61/13 41/62/13 42/63/13 33/64/13 34/65/13
+f 44/66/14 49/67/14 50/68/14 43/69/14
+f 45/54/12 37/46/12 40/49/12 46/55/12
+f 47/56/12 41/50/12 44/53/12 48/57/12
+f 48/70/15 51/71/15 49/67/15 44/66/15
+f 36/72/16 52/73/16 53/74/16 35/75/16
+f 43/69/17 50/68/17 52/73/17 36/72/17
+f 39/76/18 54/77/18 51/78/18 48/79/18
+f 46/80/19 55/81/19 56/82/19 40/83/19
+f 40/83/20 56/82/20 54/77/20 39/76/20
+f 35/75/21 53/74/21 55/81/21 46/80/21
+g Cube.001_Cube.001_Anzeige
+usemtl Anzeige
+s off
+f 4/84/22 3/85/22 28/86/22 27/87/22 26/88/22 25/89/22 8/90/22 7/91/22
+f 32/92/22 5/93/22 4/84/22 7/91/22 11/94/22 29/95/22 30/96/22 31/97/22
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr0.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr0.obj
new file mode 100644
index 0000000..cfda47d
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr0.obj
@@ -0,0 +1,128 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs3_smr0.mtl
+o Cube.002
+v 0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.334802
+v 0.000000 1.055075 -0.334802
+v 0.024805 1.055075 -0.324528
+v -0.035079 1.055075 -0.299723
+v -0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.274918
+v -0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v 0.035079 1.055075 -0.299723
+v 0.035079 1.055075 -0.299723
+v 0.024805 1.055075 -0.274918
+v -0.024805 1.055075 -0.324528
+v -0.024805 1.055075 -0.324528
+v 0.000000 1.055075 -0.264644
+v 0.000000 1.055075 -0.264644
+v 0.024805 -0.499729 -0.274918
+v 0.035080 -0.499729 -0.299723
+v 0.324981 1.306899 -0.346144
+v 0.324981 1.306899 -0.330481
+v 0.000000 0.746135 -0.330481
+v 0.000000 0.746135 -0.346144
+v -0.324981 1.306899 -0.346144
+v -0.324981 1.306899 -0.330481
+v 0.000000 -0.499729 -0.264644
+v 0.024805 -0.499729 -0.324528
+v 0.000000 -0.499729 -0.334802
+v -0.024804 -0.499729 -0.274918
+v -0.024804 -0.499729 -0.324528
+v -0.035079 -0.499729 -0.299723
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.677908 0.520935
+vt 0.657776 0.520935
+vt 0.485125 0.020439
+vt 0.677907 0.020439
+vt 0.312476 0.541067
+vt 0.312476 0.520935
+vt 0.657776 0.541067
+vt 0.292344 0.020439
+vt 0.292344 0.520935
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.492188 0.003906
+vt 1.003906 0.996094
+vt -0.023438 0.996094
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 0.0000
+vn 0.9239 0.0000 0.3827
+vn 0.8652 -0.5014 0.0000
+vn -0.8652 -0.5014 0.0000
+vn 0.3827 -0.0000 0.9239
+vn 0.3827 0.0000 -0.9239
+vn 0.9239 0.0000 -0.3827
+vn -0.3827 -0.0000 0.9239
+vn -0.9239 -0.0000 -0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn 0.0000 0.0000 -1.0000
+g Cube.002_Cube.002_Default_OBJ.001
+usemtl Default_OBJ.001
+s 1
+f 1/1/1 2/2/1 3/3/1 4/4/1
+f 5/5/1 6/6/1 7/7/1 8/8/1
+f 9/9/1 10/10/1 11/11/1 12/12/1
+f 2/2/1 13/13/1 14/14/1 3/3/1
+f 6/6/1 15/15/1 16/16/1 7/7/1
+f 10/10/1 1/1/1 4/4/1 11/11/1
+f 13/17/2 5/18/2 6/19/2 15/20/2 9/21/2 10/22/2 1/23/2 2/24/2
+f 12/25/3 17/26/3 18/27/3 11/28/3
+f 13/13/1 5/5/1 8/8/1 14/14/1
+f 19/29/4 20/30/4 21/31/4 22/32/4
+f 23/33/2 24/34/2 20/30/2 19/35/2
+f 21/31/1 20/30/1 24/34/1
+f 22/36/5 21/31/5 24/34/5 23/37/5
+f 15/15/1 9/9/1 12/12/1 16/16/1
+f 16/38/6 25/39/6 17/26/6 12/25/6
+f 4/40/7 26/41/7 27/42/7 3/43/7
+f 11/28/8 18/27/8 26/41/8 4/40/8
+f 7/44/9 28/45/9 25/46/9 16/47/9
+f 14/48/10 29/49/10 30/50/10 8/51/10
+f 8/51/11 30/50/11 28/45/11 7/44/11
+f 3/43/12 27/42/12 29/49/12 14/48/12
+g Cube.002_Cube.002_Anzeige
+usemtl Anzeige
+f 22/52/13 23/53/13 19/54/13
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr30.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr30.obj
new file mode 100644
index 0000000..bbb1b77
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr30.obj
@@ -0,0 +1,129 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs3_smr30.mtl
+o Cube.002
+v 0.167003 1.055075 -0.279363
+v 0.149388 1.055075 -0.299626
+v 0.149388 1.055075 -0.299626
+v 0.167003 1.055075 -0.279363
+v 0.102342 1.055075 -0.283885
+v 0.100469 1.055075 -0.257101
+v 0.100469 1.055075 -0.257101
+v 0.102342 1.055075 -0.283885
+v 0.144867 1.055075 -0.234966
+v 0.165129 1.055075 -0.252580
+v 0.165129 1.055075 -0.252580
+v 0.144867 1.055075 -0.234966
+v 0.122605 1.055075 -0.301499
+v 0.122605 1.055075 -0.301499
+v 0.118084 1.055075 -0.236839
+v 0.118084 1.055075 -0.236839
+v 0.144867 -0.499729 -0.234966
+v 0.165130 -0.499729 -0.252580
+v 0.445285 1.306899 -0.164770
+v 0.438296 1.306899 -0.150753
+v 0.147460 0.746135 -0.295759
+v 0.154449 0.746135 -0.309776
+v -0.136388 1.306899 -0.454782
+v -0.143377 1.306899 -0.440764
+v 0.118084 -0.499729 -0.236839
+v 0.167003 -0.499729 -0.279363
+v 0.149388 -0.499729 -0.299626
+v 0.100470 -0.499729 -0.257101
+v 0.122606 -0.499729 -0.301499
+v 0.102342 -0.499729 -0.283885
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.677908 0.520935
+vt 0.657776 0.520935
+vt 0.485125 0.020439
+vt 0.677907 0.020439
+vt 0.312476 0.541067
+vt 0.312476 0.520935
+vt 0.657776 0.541067
+vt 0.292344 0.020439
+vt 0.292344 0.520935
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.492188 0.003906
+vt 1.003906 0.996094
+vt -0.023438 0.996094
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.6561 0.0000 0.7547
+vn 0.7743 -0.5014 0.3861
+vn -0.4462 -0.0000 0.8949
+vn -0.7743 -0.5014 -0.3861
+vn -0.0698 -0.0000 0.9976
+vn 0.7547 0.0000 -0.6561
+vn 0.9976 0.0000 0.0698
+vn -0.7547 -0.0000 0.6561
+vn -0.6561 -0.0000 -0.7547
+vn -0.9976 -0.0000 -0.0698
+vn 0.0698 -0.0000 -0.9976
+vn 0.4462 0.0000 -0.8949
+g Cube.002_Cube.002_Default_OBJ.001
+usemtl Default_OBJ.001
+s 1
+f 1/1/1 2/2/1 3/3/1 4/4/1
+f 5/5/1 6/6/1 7/7/1 8/8/1
+f 9/9/1 10/10/1 11/11/1 12/12/1
+f 2/2/1 13/13/1 14/14/1 3/3/1
+f 6/6/1 15/15/1 16/16/1 7/7/1
+f 10/10/1 1/1/1 4/4/1 11/11/1
+f 13/17/2 5/18/2 6/19/2 15/20/2 9/21/2 10/22/2 1/23/2 2/24/2
+f 12/25/3 17/26/3 18/27/3 11/28/3
+f 13/13/1 5/5/1 8/8/1 14/14/1
+f 19/29/4 20/30/4 21/31/4 22/32/4
+f 23/33/2 24/34/2 20/30/2 19/35/2
+f 21/31/5 20/30/5 24/34/5
+f 22/36/6 21/31/6 24/34/6 23/37/6
+f 15/15/1 9/9/1 12/12/1 16/16/1
+f 16/38/7 25/39/7 17/26/7 12/25/7
+f 4/40/8 26/41/8 27/42/8 3/43/8
+f 11/28/9 18/27/9 26/41/9 4/40/9
+f 7/44/10 28/45/10 25/46/10 16/47/10
+f 14/48/11 29/49/11 30/50/11 8/51/11
+f 8/51/12 30/50/12 28/45/12 7/44/12
+f 3/43/13 27/42/13 29/49/13 14/48/13
+g Cube.002_Cube.002_Anzeige
+usemtl Anzeige
+f 22/52/14 23/53/14 19/54/14
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr45.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr45.obj
new file mode 100644
index 0000000..98bdecd
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr45.obj
@@ -0,0 +1,129 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs3_smr45.mtl
+o Cube.002
+v 0.247016 1.055075 -0.211936
+v 0.236741 1.055075 -0.236741
+v 0.236741 1.055075 -0.236741
+v 0.247016 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.176857 1.055075 -0.211936
+v 0.176857 1.055075 -0.211936
+v 0.187132 1.055075 -0.236741
+v 0.211936 1.055075 -0.176857
+v 0.236741 1.055075 -0.187132
+v 0.236741 1.055075 -0.187132
+v 0.211936 1.055075 -0.176857
+v 0.211936 1.055075 -0.247016
+v 0.211936 1.055075 -0.247016
+v 0.187132 1.055075 -0.187132
+v 0.187132 1.055075 -0.187132
+v 0.211936 -0.499729 -0.176857
+v 0.236741 -0.499729 -0.187131
+v 0.474557 1.306899 -0.014965
+v 0.463481 1.306899 -0.003889
+v 0.233685 0.746135 -0.233685
+v 0.244761 0.746135 -0.244761
+v 0.014965 1.306899 -0.474557
+v 0.003889 1.306899 -0.463481
+v 0.187132 -0.499729 -0.187132
+v 0.247016 -0.499729 -0.211936
+v 0.236741 -0.499729 -0.236741
+v 0.176857 -0.499729 -0.211935
+v 0.211937 -0.499729 -0.247015
+v 0.187132 -0.499729 -0.236741
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.677908 0.520935
+vt 0.657776 0.520935
+vt 0.485125 0.020439
+vt 0.677907 0.020439
+vt 0.312476 0.541067
+vt 0.312476 0.520935
+vt 0.657776 0.541067
+vt 0.292344 0.020439
+vt 0.292344 0.520935
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.492188 0.003906
+vt 1.003906 0.996094
+vt -0.023438 0.996094
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 -0.0000
+vn 0.3827 0.0000 0.9239
+vn 0.6118 -0.5014 0.6118
+vn -0.7071 -0.0000 0.7071
+vn -0.6118 -0.5014 -0.6118
+vn -0.3827 -0.0000 0.9239
+vn 0.9239 0.0000 -0.3827
+vn 0.9239 0.0000 0.3827
+vn -0.9239 -0.0000 0.3827
+vn -0.3827 -0.0000 -0.9239
+vn -0.9239 -0.0000 -0.3827
+vn 0.3827 -0.0000 -0.9239
+vn 0.7071 0.0000 -0.7071
+g Cube.002_Cube.002_Default_OBJ.001
+usemtl Default_OBJ.001
+s 1
+f 1/1/1 2/2/1 3/3/1 4/4/1
+f 5/5/1 6/6/1 7/7/1 8/8/1
+f 9/9/1 10/10/1 11/11/1 12/12/1
+f 2/2/1 13/13/1 14/14/1 3/3/1
+f 6/6/1 15/15/1 16/16/1 7/7/1
+f 10/10/1 1/1/1 4/4/1 11/11/1
+f 13/17/2 5/18/2 6/19/2 15/20/2 9/21/2 10/22/2 1/23/2 2/24/2
+f 12/25/3 17/26/3 18/27/3 11/28/3
+f 13/13/1 5/5/1 8/8/1 14/14/1
+f 19/29/4 20/30/4 21/31/4 22/32/4
+f 23/33/2 24/34/2 20/30/2 19/35/2
+f 21/31/5 20/30/5 24/34/5
+f 22/36/6 21/31/6 24/34/6 23/37/6
+f 15/15/1 9/9/1 12/12/1 16/16/1
+f 16/38/7 25/39/7 17/26/7 12/25/7
+f 4/40/8 26/41/8 27/42/8 3/43/8
+f 11/28/9 18/27/9 26/41/9 4/40/9
+f 7/44/10 28/45/10 25/46/10 16/47/10
+f 14/48/11 29/49/11 30/50/11 8/51/11
+f 8/51/12 30/50/12 28/45/12 7/44/12
+f 3/43/13 27/42/13 29/49/13 14/48/13
+g Cube.002_Cube.002_Anzeige
+usemtl Anzeige
+f 22/52/14 23/53/14 19/54/14
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr60.obj b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr60.obj
new file mode 100644
index 0000000..458cf62
--- /dev/null
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_sign_zs3_smr60.obj
@@ -0,0 +1,129 @@
+# Blender v2.93.5 OBJ File: ''
+# www.blender.org
+mtllib advtrains_signals_ks_sign_zs3_smr60.mtl
+o Cube.002
+v 0.301499 1.055075 -0.122605
+v 0.299626 1.055075 -0.149388
+v 0.299626 1.055075 -0.149388
+v 0.301499 1.055075 -0.122605
+v 0.252580 1.055075 -0.165129
+v 0.234966 1.055075 -0.144867
+v 0.234966 1.055075 -0.144867
+v 0.252580 1.055075 -0.165129
+v 0.257101 1.055075 -0.100469
+v 0.283885 1.055075 -0.102342
+v 0.283885 1.055075 -0.102342
+v 0.257101 1.055075 -0.100469
+v 0.279363 1.055075 -0.167002
+v 0.279363 1.055075 -0.167002
+v 0.236839 1.055075 -0.118084
+v 0.236839 1.055075 -0.118084
+v 0.257102 -0.499729 -0.100469
+v 0.283885 -0.499729 -0.102341
+v 0.454782 1.306899 0.136388
+v 0.440764 1.306899 0.143377
+v 0.295759 0.746135 -0.147460
+v 0.309776 0.746135 -0.154449
+v 0.164770 1.306899 -0.445285
+v 0.150753 1.306899 -0.438296
+v 0.236839 -0.499729 -0.118084
+v 0.301499 -0.499729 -0.122605
+v 0.299626 -0.499729 -0.149388
+v 0.234966 -0.499729 -0.144866
+v 0.279364 -0.499729 -0.167002
+v 0.252580 -0.499729 -0.165129
+vt 0.372863 0.578719
+vt 0.372317 0.613951
+vt 0.371666 0.613734
+vt 0.372221 0.578991
+vt 0.315877 0.640082
+vt 0.292344 0.614764
+vt 0.292986 0.614492
+vt 0.316131 0.639438
+vt 0.315346 0.553400
+vt 0.349331 0.553400
+vt 0.349077 0.554044
+vt 0.315664 0.554020
+vt 0.349861 0.640082
+vt 0.349543 0.639462
+vt 0.292889 0.579531
+vt 0.293541 0.579748
+vt 0.444102 0.636706
+vt 0.409596 0.636706
+vt 0.385196 0.612306
+vt 0.385196 0.577799
+vt 0.409596 0.553400
+vt 0.444102 0.553400
+vt 0.468502 0.577800
+vt 0.468502 0.612306
+vt 0.037160 1.987962
+vt 0.036793 0.000397
+vt 0.071486 0.000384
+vt 0.071853 1.987948
+vt 0.677908 0.520935
+vt 0.657776 0.520935
+vt 0.485125 0.020439
+vt 0.677907 0.020439
+vt 0.312476 0.541067
+vt 0.312476 0.520935
+vt 0.657776 0.541067
+vt 0.292344 0.020439
+vt 0.292344 0.520935
+vt 0.002468 1.987974
+vt 0.002100 0.000409
+vt 0.106546 1.987936
+vt 0.106179 0.000371
+vt 0.140872 0.000358
+vt 0.141239 1.987923
+vt 0.245318 1.987885
+vt 0.244951 0.000319
+vt 0.279643 0.000307
+vt 0.280011 1.987871
+vt 0.175932 1.987910
+vt 0.175565 0.000345
+vt 0.210258 0.000332
+vt 0.210625 1.987897
+vt 0.492188 0.003906
+vt 1.003906 0.996094
+vt -0.023438 0.996094
+vn 0.0000 0.0000 1.0000
+vn 0.0000 1.0000 0.0000
+vn 0.0698 0.0000 0.9976
+vn 0.3861 -0.5014 0.7743
+vn -0.8949 -0.0000 0.4462
+vn -0.3861 -0.5014 -0.7743
+vn -0.6561 -0.0000 0.7547
+vn 0.9976 0.0000 -0.0698
+vn 0.7547 0.0000 0.6561
+vn -0.9976 -0.0000 0.0698
+vn -0.0698 -0.0000 -0.9976
+vn -0.7547 -0.0000 -0.6561
+vn 0.6561 -0.0000 -0.7547
+vn 0.8949 0.0000 -0.4462
+g Cube.002_Cube.002_Default_OBJ.001
+usemtl Default_OBJ.001
+s 1
+f 1/1/1 2/2/1 3/3/1 4/4/1
+f 5/5/1 6/6/1 7/7/1 8/8/1
+f 9/9/1 10/10/1 11/11/1 12/12/1
+f 2/2/1 13/13/1 14/14/1 3/3/1
+f 6/6/1 15/15/1 16/16/1 7/7/1
+f 10/10/1 1/1/1 4/4/1 11/11/1
+f 13/17/2 5/18/2 6/19/2 15/20/2 9/21/2 10/22/2 1/23/2 2/24/2
+f 12/25/3 17/26/3 18/27/3 11/28/3
+f 13/13/1 5/5/1 8/8/1 14/14/1
+f 19/29/4 20/30/4 21/31/4 22/32/4
+f 23/33/2 24/34/2 20/30/2 19/35/2
+f 21/31/5 20/30/5 24/34/5
+f 22/36/6 21/31/6 24/34/6 23/37/6
+f 15/15/1 9/9/1 12/12/1 16/16/1
+f 16/38/7 25/39/7 17/26/7 12/25/7
+f 4/40/8 26/41/8 27/42/8 3/43/8
+f 11/28/9 18/27/9 26/41/9 4/40/9
+f 7/44/10 28/45/10 25/46/10 16/47/10
+f 14/48/11 29/49/11 30/50/11 8/51/11
+f 8/51/12 30/50/12 28/45/12 7/44/12
+f 3/43/13 27/42/13 29/49/13 14/48/13
+g Cube.002_Cube.002_Anzeige
+usemtl Anzeige
+f 22/52/14 23/53/14 19/54/14
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr0.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr0.obj
index f4ee764..f42fb22 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr0.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr0.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_bottom_smr0.mtl
-o HsVsAnzUnten_Cube.009
+o HsVsAnzUnten_Cube.008
v -0.028581 -0.495697 -0.439611
v -0.028581 -0.291434 -0.439611
v -0.028581 -0.291434 -0.496774
@@ -100,8 +100,6 @@ v 0.138251 0.431511 -0.541156
v 0.138251 0.319382 -0.541156
v 0.114848 0.483868 -0.541156
v 0.107395 0.483868 -0.541156
-v 0.107395 0.431511 -0.541156
-v 0.000000 0.319382 -0.541156
v 0.107395 0.465184 -0.541156
v 0.107395 0.465184 -0.597615
v 0.114848 0.465184 -0.541156
@@ -119,6 +117,7 @@ v 0.107395 0.449042 -0.541156
v 0.107395 0.431511 -0.566450
v 0.000000 0.449042 -0.541156
v 0.138251 0.449042 -0.541156
+v 0.107395 0.431511 -0.541156
v 0.114848 0.431511 -0.541156
v 0.000000 0.431511 -0.541156
v -0.138251 0.431511 -0.541156
@@ -126,7 +125,6 @@ v -0.138251 0.319382 -0.444371
v -0.138251 0.483868 -0.444371
v -0.138251 0.319382 -0.541156
v -0.107395 0.483868 -0.541156
-v -0.107395 0.431511 -0.541156
v -0.107395 0.465184 -0.597615
v -0.107395 0.465184 -0.541156
v -0.114848 0.465184 -0.597615
@@ -146,12 +144,12 @@ v -0.114848 0.449042 -0.541156
v -0.107395 0.431511 -0.566450
v -0.107395 0.449042 -0.541156
v -0.138251 0.449042 -0.541156
+v -0.107395 0.431511 -0.541156
v -0.114848 0.431511 -0.541156
v 0.138251 0.207254 -0.541156
v 0.138251 0.154897 -0.444371
v 0.000000 0.154897 -0.444371
v 0.107395 0.154897 -0.541156
-v 0.107395 0.207254 -0.541156
v 0.107395 0.173581 -0.566450
v 0.107395 0.173581 -0.541156
v 0.114848 0.173581 -0.566450
@@ -172,6 +170,7 @@ v 0.107395 0.207254 -0.566450
v 0.107395 0.189722 -0.541156
v 0.000000 0.189722 -0.541156
v 0.138251 0.189722 -0.541156
+v 0.107395 0.207254 -0.541156
v 0.114848 0.207254 -0.541156
v 0.000000 0.207254 -0.541156
v -0.138251 0.154897 -0.444371
@@ -180,7 +179,6 @@ v -0.138251 0.173581 -0.541156
v -0.138251 0.207254 -0.541156
v -0.114848 0.154897 -0.541156
v -0.107395 0.154897 -0.541156
-v -0.107395 0.207254 -0.541156
v -0.107395 0.173581 -0.541156
v -0.107395 0.173581 -0.566450
v -0.114848 0.173581 -0.541156
@@ -197,9 +195,11 @@ v -0.114848 0.189722 -0.566450
v -0.107395 0.189722 -0.541156
v -0.107395 0.207254 -0.566450
v -0.138251 0.189722 -0.541156
+v -0.107395 0.207254 -0.541156
v -0.114848 0.207254 -0.541156
v 0.000000 0.483868 -0.541156
v 0.000000 0.154897 -0.541156
+v 0.000000 0.319382 -0.541156
vt 0.646743 0.371805
vt 0.646743 0.142471
vt 0.705619 0.142471
@@ -646,15 +646,15 @@ vt 0.338275 0.011173
vt 0.315869 0.863702
vt 0.788504 0.988827
vt 0.743017 0.396107
-vt 0.000000 0.999918
-vt 0.000043 0.876332
-vt 0.118412 0.876373
-vt 0.236780 0.876414
-vt 0.236738 1.000000
-vt 0.000085 0.752745
-vt 0.236823 0.752827
-vt 0.118369 0.999959
-vt 0.118454 0.752786
+vt 0.003906 1.015625
+vt 0.003906 0.496094
+vt 0.500000 0.496094
+vt 1.000000 0.500000
+vt 1.000000 1.015625
+vt 0.003906 -0.019531
+vt 1.000000 -0.019531
+vt 0.500000 1.015625
+vt 0.500000 -0.019531
vn -1.0000 0.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
@@ -662,8 +662,8 @@ vn 0.0000 -0.0000 1.0000
vn 0.0000 -1.0000 -0.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 -0.8716 -0.4903
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Mast
-usemtl Mast
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Mast.009
+usemtl Mast.009
s 1
f 1/1/1 2/2/1 3/3/1
f 2/2/1 4/4/1 5/5/1
@@ -791,255 +791,255 @@ f 85/176/2 73/135/2 75/137/2
f 86/177/5 76/138/5 78/140/5
f 87/178/2 79/141/2 81/143/2
f 88/179/5 82/144/5 84/146/5
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Schirm
-usemtl Schirm
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Schirm.009
+usemtl Schirm.009
f 89/180/2 90/181/2 91/182/2
f 92/183/4 93/184/4 94/185/4
f 95/186/3 96/187/3 86/188/3
f 89/189/6 97/190/6 98/191/6
-f 101/192/6 102/193/6 74/194/6
-f 98/195/3 101/196/3 75/197/3
-f 103/198/6 104/199/6 102/193/6
-f 97/200/3 103/201/3 101/196/3
-f 105/202/3 91/203/3 103/201/3
-f 91/203/3 90/204/3 106/205/3
-f 107/206/3 78/207/3 77/208/3
-f 102/209/3 108/210/3 73/211/3
-f 102/209/3 104/212/3 109/213/3
-f 110/214/1 108/215/1 111/216/1
-f 85/217/5 73/218/5 108/219/5
-f 106/220/2 109/221/2 104/222/2
-f 86/223/2 78/224/2 107/225/2
-f 112/226/2 113/227/2 109/221/2
-f 114/228/1 111/216/1 115/229/1
-f 109/213/3 113/230/3 111/231/3
-f 110/232/3 114/233/3 116/234/3
-f 90/204/3 117/235/3 112/236/3
-f 99/237/1 115/229/1 77/238/1
-f 112/226/2 118/239/2 107/225/2
-f 113/230/7 107/206/7 115/240/7
-f 114/233/3 99/241/3 119/242/3
-f 117/235/3 95/186/3 118/243/3
-f 120/244/1 121/245/1 122/246/1
-f 121/247/4 93/184/4 92/183/4
-f 88/248/3 123/249/3 120/250/3
-f 124/251/6 122/252/6 92/253/6
-f 74/194/6 126/254/6 127/255/6
-f 75/197/3 127/256/3 124/257/3
-f 126/254/6 128/258/6 129/259/6
-f 127/256/3 129/260/3 130/261/3
-f 129/260/3 131/262/3 132/263/3
-f 133/264/3 134/265/3 131/262/3
-f 83/266/3 82/267/3 135/268/3
-f 73/211/3 136/269/3 126/270/3
-f 126/270/3 136/269/3 137/271/3
-f 138/272/2 136/273/2 139/274/2
-f 136/275/5 73/218/5 85/217/5
-f 128/276/1 137/277/1 133/278/1
-f 135/279/1 82/280/1 88/281/1
-f 137/277/1 140/282/1 141/283/1
-f 142/284/2 138/272/2 143/285/2
-f 138/286/3 140/287/3 137/271/3
-f 116/234/3 143/288/3 139/289/3
-f 141/290/3 144/291/3 134/265/3
-f 83/292/2 142/284/2 125/293/2
-f 141/283/1 140/282/1 135/279/1
-f 142/294/7 135/268/7 140/287/7
-f 119/242/3 125/295/3 143/288/3
-f 145/296/3 120/250/3 144/291/3
-f 146/297/2 94/298/2 147/299/2
-f 94/185/4 93/184/4 148/300/4
-f 86/188/3 96/187/3 146/301/3
-f 149/302/5 147/303/5 148/304/5
-f 80/305/5 151/306/5 152/307/5
-f 79/308/3 152/309/3 149/310/3
-f 151/306/5 153/311/5 154/312/5
-f 152/309/3 154/313/3 155/314/3
-f 154/313/3 156/315/3 157/316/3
-f 158/317/3 159/318/3 156/315/3
-f 77/208/3 78/207/3 160/319/3
-f 81/320/3 161/321/3 151/322/3
-f 151/322/3 161/321/3 162/323/3
-f 163/324/1 161/325/1 164/326/1
-f 161/327/6 81/328/6 87/329/6
-f 153/330/2 162/331/2 158/332/2
-f 160/333/2 78/224/2 86/223/2
-f 162/331/2 165/334/2 166/335/2
-f 167/336/1 163/324/1 168/337/1
-f 163/338/3 165/339/3 162/323/3
-f 169/340/3 168/341/3 164/342/3
-f 166/343/3 170/344/3 159/318/3
-f 77/238/1 167/336/1 150/345/1
-f 165/334/2 160/333/2 171/346/2
-f 167/347/3 160/319/3 165/339/3
-f 172/348/3 150/349/3 168/341/3
-f 171/350/3 146/301/3 170/344/3
-f 173/351/1 174/352/1 175/353/1
-f 148/300/4 93/184/4 121/247/4
-f 176/354/3 123/249/3 88/248/3
-f 173/355/5 177/356/5 178/357/5
-f 180/358/5 181/359/5 80/305/5
-f 178/360/3 180/361/3 79/308/3
-f 182/362/5 183/363/5 181/359/5
-f 177/364/3 182/365/3 180/361/3
-f 184/366/3 175/367/3 182/365/3
-f 175/367/3 174/368/3 185/369/3
-f 186/370/3 82/267/3 83/266/3
-f 181/371/3 187/372/3 81/320/3
-f 181/371/3 183/373/3 188/374/3
-f 189/375/2 187/376/2 190/377/2
-f 87/329/6 81/328/6 187/378/6
-f 185/379/1 188/380/1 183/381/1
-f 88/281/1 82/280/1 186/382/1
-f 191/383/1 192/384/1 188/380/1
-f 193/385/2 190/377/2 194/386/2
-f 188/374/3 192/387/3 190/388/3
-f 189/389/3 193/390/3 169/340/3
-f 174/368/3 195/391/3 191/392/3
-f 179/393/2 194/386/2 83/292/2
-f 196/394/1 186/382/1 192/384/1
-f 192/387/3 186/370/3 194/395/3
-f 193/390/3 179/396/3 172/348/3
-f 195/391/3 176/354/3 196/397/3
-f 91/182/2 105/398/2 89/180/2
-f 89/180/2 95/399/2 117/400/2
+f 99/192/6 100/193/6 74/194/6
+f 98/195/3 99/196/3 75/197/3
+f 101/198/6 102/199/6 100/193/6
+f 97/200/3 101/201/3 99/196/3
+f 103/202/3 91/203/3 101/201/3
+f 91/203/3 90/204/3 104/205/3
+f 105/206/3 78/207/3 77/208/3
+f 100/209/3 106/210/3 73/211/3
+f 100/209/3 102/212/3 107/213/3
+f 108/214/1 106/215/1 109/216/1
+f 85/217/5 73/218/5 106/219/5
+f 104/220/2 107/221/2 102/222/2
+f 86/223/2 78/224/2 105/225/2
+f 110/226/2 111/227/2 107/221/2
+f 112/228/1 109/216/1 113/229/1
+f 107/213/3 111/230/3 109/231/3
+f 108/232/3 112/233/3 114/234/3
+f 90/204/3 115/235/3 110/236/3
+f 116/237/1 113/229/1 77/238/1
+f 110/226/2 117/239/2 105/225/2
+f 111/230/7 105/206/7 113/240/7
+f 112/233/3 116/241/3 118/242/3
+f 115/235/3 95/186/3 117/243/3
+f 119/244/1 120/245/1 121/246/1
+f 120/247/4 93/184/4 92/183/4
+f 88/248/3 122/249/3 119/250/3
+f 123/251/6 121/252/6 92/253/6
+f 74/194/6 124/254/6 125/255/6
+f 75/197/3 125/256/3 123/257/3
+f 124/254/6 126/258/6 127/259/6
+f 125/256/3 127/260/3 128/261/3
+f 127/260/3 129/262/3 130/263/3
+f 131/264/3 132/265/3 129/262/3
+f 83/266/3 82/267/3 133/268/3
+f 73/211/3 134/269/3 124/270/3
+f 124/270/3 134/269/3 135/271/3
+f 136/272/2 134/273/2 137/274/2
+f 134/275/5 73/218/5 85/217/5
+f 126/276/1 135/277/1 131/278/1
+f 133/279/1 82/280/1 88/281/1
+f 135/277/1 138/282/1 139/283/1
+f 140/284/2 136/272/2 141/285/2
+f 136/286/3 138/287/3 135/271/3
+f 114/234/3 141/288/3 137/289/3
+f 139/290/3 142/291/3 132/265/3
+f 83/292/2 140/284/2 143/293/2
+f 139/283/1 138/282/1 133/279/1
+f 140/294/7 133/268/7 138/287/7
+f 118/242/3 143/295/3 141/288/3
+f 144/296/3 119/250/3 142/291/3
+f 145/297/2 94/298/2 146/299/2
+f 94/185/4 93/184/4 147/300/4
+f 86/188/3 96/187/3 145/301/3
+f 148/302/5 146/303/5 147/304/5
+f 80/305/5 149/306/5 150/307/5
+f 79/308/3 150/309/3 148/310/3
+f 149/306/5 151/311/5 152/312/5
+f 150/309/3 152/313/3 153/314/3
+f 152/313/3 154/315/3 155/316/3
+f 156/317/3 157/318/3 154/315/3
+f 77/208/3 78/207/3 158/319/3
+f 81/320/3 159/321/3 149/322/3
+f 149/322/3 159/321/3 160/323/3
+f 161/324/1 159/325/1 162/326/1
+f 159/327/6 81/328/6 87/329/6
+f 151/330/2 160/331/2 156/332/2
+f 158/333/2 78/224/2 86/223/2
+f 160/331/2 163/334/2 164/335/2
+f 165/336/1 161/324/1 166/337/1
+f 161/338/3 163/339/3 160/323/3
+f 167/340/3 166/341/3 162/342/3
+f 164/343/3 168/344/3 157/318/3
+f 77/238/1 165/336/1 169/345/1
+f 163/334/2 158/333/2 170/346/2
+f 165/347/3 158/319/3 163/339/3
+f 171/348/3 169/349/3 166/341/3
+f 170/350/3 145/301/3 168/344/3
+f 172/351/1 173/352/1 174/353/1
+f 147/300/4 93/184/4 120/247/4
+f 175/354/3 122/249/3 88/248/3
+f 172/355/5 176/356/5 177/357/5
+f 178/358/5 179/359/5 80/305/5
+f 177/360/3 178/361/3 79/308/3
+f 180/362/5 181/363/5 179/359/5
+f 176/364/3 180/365/3 178/361/3
+f 182/366/3 174/367/3 180/365/3
+f 174/367/3 173/368/3 183/369/3
+f 184/370/3 82/267/3 83/266/3
+f 179/371/3 185/372/3 81/320/3
+f 179/371/3 181/373/3 186/374/3
+f 187/375/2 185/376/2 188/377/2
+f 87/329/6 81/328/6 185/378/6
+f 183/379/1 186/380/1 181/381/1
+f 88/281/1 82/280/1 184/382/1
+f 189/383/1 190/384/1 186/380/1
+f 191/385/2 188/377/2 192/386/2
+f 186/374/3 190/387/3 188/388/3
+f 187/389/3 191/390/3 167/340/3
+f 173/368/3 193/391/3 189/392/3
+f 194/393/2 192/386/2 83/292/2
+f 195/394/1 184/382/1 190/384/1
+f 190/387/3 184/370/3 192/395/3
+f 191/390/3 194/396/3 171/348/3
+f 193/391/3 175/354/3 195/397/3
+f 91/182/2 103/398/2 89/180/2
+f 89/180/2 95/399/2 115/400/2
f 96/401/2 95/399/2 94/298/2
-f 117/400/2 90/181/2 89/180/2
+f 115/400/2 90/181/2 89/180/2
f 94/298/2 95/399/2 89/180/2
f 89/402/4 92/183/4 94/185/4
-f 118/243/3 95/186/3 86/188/3
-f 98/191/6 197/403/6 92/253/6
+f 117/243/3 95/186/3 86/188/3
+f 98/191/6 196/403/6 92/253/6
f 92/253/6 89/189/6 98/191/6
-f 105/404/6 97/190/6 89/189/6
-f 75/405/6 101/192/6 74/194/6
-f 197/406/3 98/195/3 75/197/3
-f 101/192/6 103/198/6 102/193/6
-f 98/195/3 97/200/3 101/196/3
-f 97/200/3 105/202/3 103/201/3
-f 103/201/3 91/203/3 106/205/3
-f 115/240/3 107/206/3 77/208/3
-f 74/407/3 102/209/3 73/211/3
-f 108/210/3 102/209/3 109/213/3
-f 114/228/1 110/214/1 111/216/1
-f 110/408/5 85/217/5 108/219/5
-f 103/409/2 106/220/2 104/222/2
-f 118/239/2 86/223/2 107/225/2
-f 106/220/2 112/226/2 109/221/2
-f 99/237/1 114/228/1 115/229/1
-f 108/210/3 109/213/3 111/231/3
-f 85/410/3 110/232/3 116/234/3
-f 106/205/3 90/204/3 112/236/3
-f 76/411/1 99/237/1 77/238/1
-f 113/227/2 112/226/2 107/225/2
-f 111/231/7 113/230/7 115/240/7
-f 116/234/3 114/233/3 119/242/3
-f 112/236/3 117/235/3 118/243/3
-f 122/246/1 132/412/1 131/413/1
-f 131/413/1 134/414/1 122/246/1
-f 144/415/1 120/244/1 122/246/1
-f 123/416/1 121/245/1 120/244/1
-f 122/246/1 134/414/1 144/415/1
-f 122/417/4 121/247/4 92/183/4
-f 145/296/3 88/248/3 120/250/3
-f 92/253/6 197/403/6 124/251/6
-f 124/251/6 130/418/6 122/252/6
-f 132/419/6 122/252/6 130/418/6
-f 75/405/6 74/194/6 127/255/6
-f 197/406/3 75/197/3 124/257/3
-f 127/255/6 126/254/6 129/259/6
-f 124/257/3 127/256/3 130/261/3
-f 130/261/3 129/260/3 132/263/3
-f 129/260/3 133/264/3 131/262/3
-f 142/294/3 83/266/3 135/268/3
-f 74/407/3 73/211/3 126/270/3
-f 128/420/3 126/270/3 137/271/3
-f 143/285/2 138/272/2 139/274/2
-f 139/421/5 136/275/5 85/217/5
-f 129/422/1 128/276/1 133/278/1
-f 145/423/1 135/279/1 88/281/1
-f 133/278/1 137/277/1 141/283/1
-f 125/293/2 142/284/2 143/285/2
-f 136/269/3 138/286/3 137/271/3
-f 85/410/3 116/234/3 139/289/3
-f 133/264/3 141/290/3 134/265/3
-f 84/424/2 83/292/2 125/293/2
-f 145/423/1 141/283/1 135/279/1
-f 138/286/7 142/294/7 140/287/7
-f 116/234/3 119/242/3 143/288/3
-f 141/290/3 145/296/3 144/291/3
-f 147/299/2 157/425/2 156/426/2
-f 156/426/2 159/427/2 147/299/2
-f 170/428/2 146/297/2 147/299/2
-f 96/401/2 94/298/2 146/297/2
-f 147/299/2 159/427/2 170/428/2
-f 147/429/4 94/185/4 148/300/4
-f 171/350/3 86/188/3 146/301/3
-f 148/304/5 198/430/5 149/302/5
-f 149/302/5 155/431/5 147/303/5
-f 157/432/5 147/303/5 155/431/5
-f 79/433/5 80/305/5 152/307/5
-f 198/434/3 79/308/3 149/310/3
-f 152/307/5 151/306/5 154/312/5
-f 149/310/3 152/309/3 155/314/3
-f 155/314/3 154/313/3 157/316/3
-f 154/313/3 158/317/3 156/315/3
-f 167/347/3 77/208/3 160/319/3
-f 80/435/3 81/320/3 151/322/3
-f 153/436/3 151/322/3 162/323/3
-f 168/337/1 163/324/1 164/326/1
-f 164/437/6 161/327/6 87/329/6
-f 154/438/2 153/330/2 158/332/2
-f 171/346/2 160/333/2 86/223/2
-f 158/332/2 162/331/2 166/335/2
-f 150/345/1 167/336/1 168/337/1
-f 161/321/3 163/338/3 162/323/3
-f 87/439/3 169/340/3 164/342/3
-f 158/317/3 166/343/3 159/318/3
-f 76/411/1 77/238/1 150/345/1
-f 166/335/2 165/334/2 171/346/2
-f 163/338/3 167/347/3 165/339/3
-f 169/340/3 172/348/3 168/341/3
-f 166/343/3 171/350/3 170/344/3
-f 175/353/1 184/440/1 173/351/1
-f 173/351/1 176/441/1 195/442/1
-f 123/416/1 176/441/1 121/245/1
-f 195/442/1 174/352/1 173/351/1
-f 121/245/1 176/441/1 173/351/1
-f 173/443/4 148/300/4 121/247/4
-f 196/397/3 176/354/3 88/248/3
-f 178/357/5 198/430/5 148/304/5
-f 148/304/5 173/355/5 178/357/5
-f 184/444/5 177/356/5 173/355/5
-f 79/433/5 180/358/5 80/305/5
-f 198/434/3 178/360/3 79/308/3
-f 180/358/5 182/362/5 181/359/5
-f 178/360/3 177/364/3 180/361/3
-f 177/364/3 184/366/3 182/365/3
-f 182/365/3 175/367/3 185/369/3
-f 194/395/3 186/370/3 83/266/3
-f 80/435/3 181/371/3 81/320/3
-f 187/372/3 181/371/3 188/374/3
-f 193/385/2 189/375/2 190/377/2
-f 189/445/6 87/329/6 187/378/6
-f 182/446/1 185/379/1 183/381/1
-f 196/394/1 88/281/1 186/382/1
-f 185/379/1 191/383/1 188/380/1
-f 179/393/2 193/385/2 194/386/2
-f 187/372/3 188/374/3 190/388/3
-f 87/439/3 189/389/3 169/340/3
-f 185/369/3 174/368/3 191/392/3
-f 84/424/2 179/393/2 83/292/2
-f 191/383/1 196/394/1 192/384/1
-f 190/388/3 192/387/3 194/395/3
-f 169/340/3 193/390/3 172/348/3
-f 191/392/3 195/391/3 196/397/3
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Anzeige
-usemtl Anzeige
-f 99/447/3 76/448/3 100/449/3
-f 100/449/3 84/450/3 125/451/3
-f 100/449/3 76/448/3 150/452/3
-f 179/453/3 84/450/3 100/449/3
-f 119/454/3 99/447/3 100/449/3
-f 119/454/3 100/449/3 125/451/3
-f 172/455/3 100/449/3 150/452/3
-f 172/455/3 179/453/3 100/449/3
+f 103/404/6 97/190/6 89/189/6
+f 75/405/6 99/192/6 74/194/6
+f 196/406/3 98/195/3 75/197/3
+f 99/192/6 101/198/6 100/193/6
+f 98/195/3 97/200/3 99/196/3
+f 97/200/3 103/202/3 101/201/3
+f 101/201/3 91/203/3 104/205/3
+f 113/240/3 105/206/3 77/208/3
+f 74/407/3 100/209/3 73/211/3
+f 106/210/3 100/209/3 107/213/3
+f 112/228/1 108/214/1 109/216/1
+f 108/408/5 85/217/5 106/219/5
+f 101/409/2 104/220/2 102/222/2
+f 117/239/2 86/223/2 105/225/2
+f 104/220/2 110/226/2 107/221/2
+f 116/237/1 112/228/1 113/229/1
+f 106/210/3 107/213/3 109/231/3
+f 85/410/3 108/232/3 114/234/3
+f 104/205/3 90/204/3 110/236/3
+f 76/411/1 116/237/1 77/238/1
+f 111/227/2 110/226/2 105/225/2
+f 109/231/7 111/230/7 113/240/7
+f 114/234/3 112/233/3 118/242/3
+f 110/236/3 115/235/3 117/243/3
+f 121/246/1 130/412/1 129/413/1
+f 129/413/1 132/414/1 121/246/1
+f 142/415/1 119/244/1 121/246/1
+f 122/416/1 120/245/1 119/244/1
+f 121/246/1 132/414/1 142/415/1
+f 121/417/4 120/247/4 92/183/4
+f 144/296/3 88/248/3 119/250/3
+f 92/253/6 196/403/6 123/251/6
+f 123/251/6 128/418/6 121/252/6
+f 130/419/6 121/252/6 128/418/6
+f 75/405/6 74/194/6 125/255/6
+f 196/406/3 75/197/3 123/257/3
+f 125/255/6 124/254/6 127/259/6
+f 123/257/3 125/256/3 128/261/3
+f 128/261/3 127/260/3 130/263/3
+f 127/260/3 131/264/3 129/262/3
+f 140/294/3 83/266/3 133/268/3
+f 74/407/3 73/211/3 124/270/3
+f 126/420/3 124/270/3 135/271/3
+f 141/285/2 136/272/2 137/274/2
+f 137/421/5 134/275/5 85/217/5
+f 127/422/1 126/276/1 131/278/1
+f 144/423/1 133/279/1 88/281/1
+f 131/278/1 135/277/1 139/283/1
+f 143/293/2 140/284/2 141/285/2
+f 134/269/3 136/286/3 135/271/3
+f 85/410/3 114/234/3 137/289/3
+f 131/264/3 139/290/3 132/265/3
+f 84/424/2 83/292/2 143/293/2
+f 144/423/1 139/283/1 133/279/1
+f 136/286/7 140/294/7 138/287/7
+f 114/234/3 118/242/3 141/288/3
+f 139/290/3 144/296/3 142/291/3
+f 146/299/2 155/425/2 154/426/2
+f 154/426/2 157/427/2 146/299/2
+f 168/428/2 145/297/2 146/299/2
+f 96/401/2 94/298/2 145/297/2
+f 146/299/2 157/427/2 168/428/2
+f 146/429/4 94/185/4 147/300/4
+f 170/350/3 86/188/3 145/301/3
+f 147/304/5 197/430/5 148/302/5
+f 148/302/5 153/431/5 146/303/5
+f 155/432/5 146/303/5 153/431/5
+f 79/433/5 80/305/5 150/307/5
+f 197/434/3 79/308/3 148/310/3
+f 150/307/5 149/306/5 152/312/5
+f 148/310/3 150/309/3 153/314/3
+f 153/314/3 152/313/3 155/316/3
+f 152/313/3 156/317/3 154/315/3
+f 165/347/3 77/208/3 158/319/3
+f 80/435/3 81/320/3 149/322/3
+f 151/436/3 149/322/3 160/323/3
+f 166/337/1 161/324/1 162/326/1
+f 162/437/6 159/327/6 87/329/6
+f 152/438/2 151/330/2 156/332/2
+f 170/346/2 158/333/2 86/223/2
+f 156/332/2 160/331/2 164/335/2
+f 169/345/1 165/336/1 166/337/1
+f 159/321/3 161/338/3 160/323/3
+f 87/439/3 167/340/3 162/342/3
+f 156/317/3 164/343/3 157/318/3
+f 76/411/1 77/238/1 169/345/1
+f 164/335/2 163/334/2 170/346/2
+f 161/338/3 165/347/3 163/339/3
+f 167/340/3 171/348/3 166/341/3
+f 164/343/3 170/350/3 168/344/3
+f 174/353/1 182/440/1 172/351/1
+f 172/351/1 175/441/1 193/442/1
+f 122/416/1 175/441/1 120/245/1
+f 193/442/1 173/352/1 172/351/1
+f 120/245/1 175/441/1 172/351/1
+f 172/443/4 147/300/4 120/247/4
+f 195/397/3 175/354/3 88/248/3
+f 177/357/5 197/430/5 147/304/5
+f 147/304/5 172/355/5 177/357/5
+f 182/444/5 176/356/5 172/355/5
+f 79/433/5 178/358/5 80/305/5
+f 197/434/3 177/360/3 79/308/3
+f 178/358/5 180/362/5 179/359/5
+f 177/360/3 176/364/3 178/361/3
+f 176/364/3 182/366/3 180/365/3
+f 180/365/3 174/367/3 183/369/3
+f 192/395/3 184/370/3 83/266/3
+f 80/435/3 179/371/3 81/320/3
+f 185/372/3 179/371/3 186/374/3
+f 191/385/2 187/375/2 188/377/2
+f 187/445/6 87/329/6 185/378/6
+f 180/446/1 183/379/1 181/381/1
+f 195/394/1 88/281/1 184/382/1
+f 183/379/1 189/383/1 186/380/1
+f 194/393/2 191/385/2 192/386/2
+f 185/372/3 186/374/3 188/388/3
+f 87/439/3 187/389/3 167/340/3
+f 183/369/3 173/368/3 189/392/3
+f 84/424/2 194/393/2 83/292/2
+f 189/383/1 195/394/1 190/384/1
+f 188/388/3 190/387/3 192/395/3
+f 167/340/3 191/390/3 171/348/3
+f 189/392/3 193/391/3 195/397/3
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Anzeige.009
+usemtl Anzeige.009
+f 116/447/3 76/448/3 198/449/3
+f 198/449/3 84/450/3 143/451/3
+f 198/449/3 76/448/3 169/452/3
+f 194/453/3 84/450/3 198/449/3
+f 118/454/3 116/447/3 198/449/3
+f 118/454/3 198/449/3 143/451/3
+f 171/455/3 198/449/3 169/452/3
+f 171/455/3 194/453/3 198/449/3
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr30.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr30.obj
index 6ef4763..3436d77 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr30.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr30.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_bottom_smr30.mtl
-o HsVsAnzUnten_Cube.009
+o HsVsAnzUnten_Cube.008
v 0.170575 -0.495697 -0.406176
v 0.170575 -0.291434 -0.406176
v 0.196081 -0.291434 -0.457333
@@ -100,8 +100,6 @@ v 0.365188 0.431511 -0.422612
v 0.365188 0.319382 -0.422612
v 0.344244 0.483868 -0.433054
v 0.337574 0.483868 -0.436380
-v 0.337574 0.431511 -0.436380
-v 0.241463 0.319382 -0.484299
v 0.337574 0.465184 -0.436380
v 0.362766 0.465184 -0.486907
v 0.344244 0.465184 -0.433054
@@ -119,6 +117,7 @@ v 0.337574 0.449042 -0.436380
v 0.348860 0.431511 -0.459016
v 0.241463 0.449042 -0.484299
v 0.365188 0.449042 -0.422612
+v 0.337574 0.431511 -0.436380
v 0.344244 0.431511 -0.433054
v 0.241463 0.431511 -0.484299
v 0.117737 0.431511 -0.545986
@@ -126,7 +125,6 @@ v 0.074552 0.319382 -0.459370
v 0.074552 0.483868 -0.459370
v 0.117737 0.319382 -0.545986
v 0.145351 0.483868 -0.532219
-v 0.145351 0.431511 -0.532219
v 0.170543 0.465184 -0.582746
v 0.145351 0.465184 -0.532219
v 0.163873 0.465184 -0.586071
@@ -146,12 +144,12 @@ v 0.138681 0.449042 -0.535544
v 0.156637 0.431511 -0.554855
v 0.145351 0.449042 -0.532219
v 0.117737 0.449042 -0.545986
+v 0.145351 0.431511 -0.532219
v 0.138681 0.431511 -0.535544
v 0.365188 0.207254 -0.422612
v 0.322003 0.154897 -0.335996
v 0.198277 0.154897 -0.397683
v 0.337574 0.154897 -0.436380
-v 0.337574 0.207254 -0.436380
v 0.348860 0.173581 -0.459016
v 0.337574 0.173581 -0.436380
v 0.355530 0.173581 -0.455691
@@ -172,6 +170,7 @@ v 0.348860 0.207254 -0.459016
v 0.337574 0.189722 -0.436380
v 0.241463 0.189722 -0.484299
v 0.365188 0.189722 -0.422612
+v 0.337574 0.207254 -0.436380
v 0.344244 0.207254 -0.433054
v 0.241463 0.207254 -0.484299
v 0.074552 0.154897 -0.459370
@@ -180,7 +179,6 @@ v 0.117737 0.173581 -0.545986
v 0.117737 0.207254 -0.545986
v 0.138681 0.154897 -0.535544
v 0.145351 0.154897 -0.532219
-v 0.145351 0.207254 -0.532219
v 0.145351 0.173581 -0.532219
v 0.156637 0.173581 -0.554855
v 0.138681 0.173581 -0.535544
@@ -197,9 +195,11 @@ v 0.149967 0.189722 -0.558180
v 0.145351 0.189722 -0.532219
v 0.156637 0.207254 -0.554855
v 0.117737 0.189722 -0.545986
+v 0.145351 0.207254 -0.532219
v 0.138681 0.207254 -0.535544
v 0.241463 0.483868 -0.484299
v 0.241463 0.154897 -0.484299
+v 0.241463 0.319382 -0.484299
vt 0.646743 0.371805
vt 0.646743 0.142471
vt 0.705619 0.142471
@@ -646,15 +646,15 @@ vt 0.338275 0.011173
vt 0.315869 0.863702
vt 0.788504 0.988827
vt 0.743017 0.396107
-vt 0.000000 0.999918
-vt 0.000043 0.876332
-vt 0.118412 0.876373
-vt 0.236780 0.876414
-vt 0.236738 1.000000
-vt 0.000085 0.752745
-vt 0.236823 0.752827
-vt 0.118369 0.999959
-vt 0.118454 0.752786
+vt 0.003906 1.015625
+vt 0.003906 0.496094
+vt 0.500000 0.496094
+vt 1.000000 0.500000
+vt 1.000000 1.015625
+vt 0.003906 -0.019531
+vt 1.000000 -0.019531
+vt 0.500000 1.015625
+vt 0.500000 -0.019531
vn -0.8949 0.0000 -0.4462
vn 0.8949 0.0000 0.4462
vn 0.4462 0.0000 -0.8949
@@ -662,8 +662,8 @@ vn -0.4462 0.0000 0.8949
vn 0.0000 -1.0000 -0.0000
vn 0.0000 1.0000 0.0000
vn 0.2188 -0.8716 -0.4388
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Mast
-usemtl Mast
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Mast.009
+usemtl Mast.009
s 1
f 1/1/1 2/2/1 3/3/1
f 2/2/1 4/4/1 5/5/1
@@ -791,255 +791,255 @@ f 85/176/2 73/135/2 75/137/2
f 86/177/5 76/138/5 78/140/5
f 87/178/2 79/141/2 81/143/2
f 88/179/5 82/144/5 84/146/5
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Schirm
-usemtl Schirm
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Schirm.009
+usemtl Schirm.009
f 89/180/2 90/181/2 91/182/2
f 92/183/4 93/184/4 94/185/4
f 95/186/3 96/187/3 86/188/3
f 89/189/6 97/190/6 98/191/6
-f 101/192/6 102/193/6 74/194/6
-f 98/195/3 101/196/3 75/197/3
-f 103/198/6 104/199/6 102/193/6
-f 97/200/3 103/201/3 101/196/3
-f 105/202/3 91/203/3 103/201/3
-f 91/203/3 90/204/3 106/205/3
-f 107/206/3 78/207/3 77/208/3
-f 102/209/3 108/210/3 73/211/3
-f 102/209/3 104/212/3 109/213/3
-f 110/214/1 108/215/1 111/216/1
-f 85/217/5 73/218/5 108/219/5
-f 106/220/2 109/221/2 104/222/2
-f 86/223/2 78/224/2 107/225/2
-f 112/226/2 113/227/2 109/221/2
-f 114/228/1 111/216/1 115/229/1
-f 109/213/3 113/230/3 111/231/3
-f 110/232/3 114/233/3 116/234/3
-f 90/204/3 117/235/3 112/236/3
-f 99/237/1 115/229/1 77/238/1
-f 112/226/2 118/239/2 107/225/2
-f 113/230/7 107/206/7 115/240/7
-f 114/233/3 99/241/3 119/242/3
-f 117/235/3 95/186/3 118/243/3
-f 120/244/1 121/245/1 122/246/1
-f 121/247/4 93/184/4 92/183/4
-f 88/248/3 123/249/3 120/250/3
-f 124/251/6 122/252/6 92/253/6
-f 74/194/6 126/254/6 127/255/6
-f 75/197/3 127/256/3 124/257/3
-f 126/254/6 128/258/6 129/259/6
-f 127/256/3 129/260/3 130/261/3
-f 129/260/3 131/262/3 132/263/3
-f 133/264/3 134/265/3 131/262/3
-f 83/266/3 82/267/3 135/268/3
-f 73/211/3 136/269/3 126/270/3
-f 126/270/3 136/269/3 137/271/3
-f 138/272/2 136/273/2 139/274/2
-f 136/275/5 73/218/5 85/217/5
-f 128/276/1 137/277/1 133/278/1
-f 135/279/1 82/280/1 88/281/1
-f 137/277/1 140/282/1 141/283/1
-f 142/284/2 138/272/2 143/285/2
-f 138/286/3 140/287/3 137/271/3
-f 116/234/3 143/288/3 139/289/3
-f 141/290/3 144/291/3 134/265/3
-f 83/292/2 142/284/2 125/293/2
-f 141/283/1 140/282/1 135/279/1
-f 142/294/7 135/268/7 140/287/7
-f 119/242/3 125/295/3 143/288/3
-f 145/296/3 120/250/3 144/291/3
-f 146/297/2 94/298/2 147/299/2
-f 94/185/4 93/184/4 148/300/4
-f 86/188/3 96/187/3 146/301/3
-f 149/302/5 147/303/5 148/304/5
-f 80/305/5 151/306/5 152/307/5
-f 79/308/3 152/309/3 149/310/3
-f 151/306/5 153/311/5 154/312/5
-f 152/309/3 154/313/3 155/314/3
-f 154/313/3 156/315/3 157/316/3
-f 158/317/3 159/318/3 156/315/3
-f 77/208/3 78/207/3 160/319/3
-f 81/320/3 161/321/3 151/322/3
-f 151/322/3 161/321/3 162/323/3
-f 163/324/1 161/325/1 164/326/1
-f 161/327/6 81/328/6 87/329/6
-f 153/330/2 162/331/2 158/332/2
-f 160/333/2 78/224/2 86/223/2
-f 162/331/2 165/334/2 166/335/2
-f 167/336/1 163/324/1 168/337/1
-f 163/338/3 165/339/3 162/323/3
-f 169/340/3 168/341/3 164/342/3
-f 166/343/3 170/344/3 159/318/3
-f 77/238/1 167/336/1 150/345/1
-f 165/334/2 160/333/2 171/346/2
-f 167/347/3 160/319/3 165/339/3
-f 172/348/3 150/349/3 168/341/3
-f 171/350/3 146/301/3 170/344/3
-f 173/351/1 174/352/1 175/353/1
-f 148/300/4 93/184/4 121/247/4
-f 176/354/3 123/249/3 88/248/3
-f 173/355/5 177/356/5 178/357/5
-f 180/358/5 181/359/5 80/305/5
-f 178/360/3 180/361/3 79/308/3
-f 182/362/5 183/363/5 181/359/5
-f 177/364/3 182/365/3 180/361/3
-f 184/366/3 175/367/3 182/365/3
-f 175/367/3 174/368/3 185/369/3
-f 186/370/3 82/267/3 83/266/3
-f 181/371/3 187/372/3 81/320/3
-f 181/371/3 183/373/3 188/374/3
-f 189/375/2 187/376/2 190/377/2
-f 87/329/6 81/328/6 187/378/6
-f 185/379/1 188/380/1 183/381/1
-f 88/281/1 82/280/1 186/382/1
-f 191/383/1 192/384/1 188/380/1
-f 193/385/2 190/377/2 194/386/2
-f 188/374/3 192/387/3 190/388/3
-f 189/389/3 193/390/3 169/340/3
-f 174/368/3 195/391/3 191/392/3
-f 179/393/2 194/386/2 83/292/2
-f 196/394/1 186/382/1 192/384/1
-f 192/387/3 186/370/3 194/395/3
-f 193/390/3 179/396/3 172/348/3
-f 195/391/3 176/354/3 196/397/3
-f 91/182/2 105/398/2 89/180/2
-f 89/180/2 95/399/2 117/400/2
+f 99/192/6 100/193/6 74/194/6
+f 98/195/3 99/196/3 75/197/3
+f 101/198/6 102/199/6 100/193/6
+f 97/200/3 101/201/3 99/196/3
+f 103/202/3 91/203/3 101/201/3
+f 91/203/3 90/204/3 104/205/3
+f 105/206/3 78/207/3 77/208/3
+f 100/209/3 106/210/3 73/211/3
+f 100/209/3 102/212/3 107/213/3
+f 108/214/1 106/215/1 109/216/1
+f 85/217/5 73/218/5 106/219/5
+f 104/220/2 107/221/2 102/222/2
+f 86/223/2 78/224/2 105/225/2
+f 110/226/2 111/227/2 107/221/2
+f 112/228/1 109/216/1 113/229/1
+f 107/213/3 111/230/3 109/231/3
+f 108/232/3 112/233/3 114/234/3
+f 90/204/3 115/235/3 110/236/3
+f 116/237/1 113/229/1 77/238/1
+f 110/226/2 117/239/2 105/225/2
+f 111/230/7 105/206/7 113/240/7
+f 112/233/3 116/241/3 118/242/3
+f 115/235/3 95/186/3 117/243/3
+f 119/244/1 120/245/1 121/246/1
+f 120/247/4 93/184/4 92/183/4
+f 88/248/3 122/249/3 119/250/3
+f 123/251/6 121/252/6 92/253/6
+f 74/194/6 124/254/6 125/255/6
+f 75/197/3 125/256/3 123/257/3
+f 124/254/6 126/258/6 127/259/6
+f 125/256/3 127/260/3 128/261/3
+f 127/260/3 129/262/3 130/263/3
+f 131/264/3 132/265/3 129/262/3
+f 83/266/3 82/267/3 133/268/3
+f 73/211/3 134/269/3 124/270/3
+f 124/270/3 134/269/3 135/271/3
+f 136/272/2 134/273/2 137/274/2
+f 134/275/5 73/218/5 85/217/5
+f 126/276/1 135/277/1 131/278/1
+f 133/279/1 82/280/1 88/281/1
+f 135/277/1 138/282/1 139/283/1
+f 140/284/2 136/272/2 141/285/2
+f 136/286/3 138/287/3 135/271/3
+f 114/234/3 141/288/3 137/289/3
+f 139/290/3 142/291/3 132/265/3
+f 83/292/2 140/284/2 143/293/2
+f 139/283/1 138/282/1 133/279/1
+f 140/294/7 133/268/7 138/287/7
+f 118/242/3 143/295/3 141/288/3
+f 144/296/3 119/250/3 142/291/3
+f 145/297/2 94/298/2 146/299/2
+f 94/185/4 93/184/4 147/300/4
+f 86/188/3 96/187/3 145/301/3
+f 148/302/5 146/303/5 147/304/5
+f 80/305/5 149/306/5 150/307/5
+f 79/308/3 150/309/3 148/310/3
+f 149/306/5 151/311/5 152/312/5
+f 150/309/3 152/313/3 153/314/3
+f 152/313/3 154/315/3 155/316/3
+f 156/317/3 157/318/3 154/315/3
+f 77/208/3 78/207/3 158/319/3
+f 81/320/3 159/321/3 149/322/3
+f 149/322/3 159/321/3 160/323/3
+f 161/324/1 159/325/1 162/326/1
+f 159/327/6 81/328/6 87/329/6
+f 151/330/2 160/331/2 156/332/2
+f 158/333/2 78/224/2 86/223/2
+f 160/331/2 163/334/2 164/335/2
+f 165/336/1 161/324/1 166/337/1
+f 161/338/3 163/339/3 160/323/3
+f 167/340/3 166/341/3 162/342/3
+f 164/343/3 168/344/3 157/318/3
+f 77/238/1 165/336/1 169/345/1
+f 163/334/2 158/333/2 170/346/2
+f 165/347/3 158/319/3 163/339/3
+f 171/348/3 169/349/3 166/341/3
+f 170/350/3 145/301/3 168/344/3
+f 172/351/1 173/352/1 174/353/1
+f 147/300/4 93/184/4 120/247/4
+f 175/354/3 122/249/3 88/248/3
+f 172/355/5 176/356/5 177/357/5
+f 178/358/5 179/359/5 80/305/5
+f 177/360/3 178/361/3 79/308/3
+f 180/362/5 181/363/5 179/359/5
+f 176/364/3 180/365/3 178/361/3
+f 182/366/3 174/367/3 180/365/3
+f 174/367/3 173/368/3 183/369/3
+f 184/370/3 82/267/3 83/266/3
+f 179/371/3 185/372/3 81/320/3
+f 179/371/3 181/373/3 186/374/3
+f 187/375/2 185/376/2 188/377/2
+f 87/329/6 81/328/6 185/378/6
+f 183/379/1 186/380/1 181/381/1
+f 88/281/1 82/280/1 184/382/1
+f 189/383/1 190/384/1 186/380/1
+f 191/385/2 188/377/2 192/386/2
+f 186/374/3 190/387/3 188/388/3
+f 187/389/3 191/390/3 167/340/3
+f 173/368/3 193/391/3 189/392/3
+f 194/393/2 192/386/2 83/292/2
+f 195/394/1 184/382/1 190/384/1
+f 190/387/3 184/370/3 192/395/3
+f 191/390/3 194/396/3 171/348/3
+f 193/391/3 175/354/3 195/397/3
+f 91/182/2 103/398/2 89/180/2
+f 89/180/2 95/399/2 115/400/2
f 96/401/2 95/399/2 94/298/2
-f 117/400/2 90/181/2 89/180/2
+f 115/400/2 90/181/2 89/180/2
f 94/298/2 95/399/2 89/180/2
f 89/402/4 92/183/4 94/185/4
-f 118/243/3 95/186/3 86/188/3
-f 98/191/6 197/403/6 92/253/6
+f 117/243/3 95/186/3 86/188/3
+f 98/191/6 196/403/6 92/253/6
f 92/253/6 89/189/6 98/191/6
-f 105/404/6 97/190/6 89/189/6
-f 75/405/6 101/192/6 74/194/6
-f 197/406/3 98/195/3 75/197/3
-f 101/192/6 103/198/6 102/193/6
-f 98/195/3 97/200/3 101/196/3
-f 97/200/3 105/202/3 103/201/3
-f 103/201/3 91/203/3 106/205/3
-f 115/240/3 107/206/3 77/208/3
-f 74/407/3 102/209/3 73/211/3
-f 108/210/3 102/209/3 109/213/3
-f 114/228/1 110/214/1 111/216/1
-f 110/408/5 85/217/5 108/219/5
-f 103/409/2 106/220/2 104/222/2
-f 118/239/2 86/223/2 107/225/2
-f 106/220/2 112/226/2 109/221/2
-f 99/237/1 114/228/1 115/229/1
-f 108/210/3 109/213/3 111/231/3
-f 85/410/3 110/232/3 116/234/3
-f 106/205/3 90/204/3 112/236/3
-f 76/411/1 99/237/1 77/238/1
-f 113/227/2 112/226/2 107/225/2
-f 111/231/7 113/230/7 115/240/7
-f 116/234/3 114/233/3 119/242/3
-f 112/236/3 117/235/3 118/243/3
-f 122/246/1 132/412/1 131/413/1
-f 131/413/1 134/414/1 122/246/1
-f 144/415/1 120/244/1 122/246/1
-f 123/416/1 121/245/1 120/244/1
-f 122/246/1 134/414/1 144/415/1
-f 122/417/4 121/247/4 92/183/4
-f 145/296/3 88/248/3 120/250/3
-f 92/253/6 197/403/6 124/251/6
-f 124/251/6 130/418/6 122/252/6
-f 132/419/6 122/252/6 130/418/6
-f 75/405/6 74/194/6 127/255/6
-f 197/406/3 75/197/3 124/257/3
-f 127/255/6 126/254/6 129/259/6
-f 124/257/3 127/256/3 130/261/3
-f 130/261/3 129/260/3 132/263/3
-f 129/260/3 133/264/3 131/262/3
-f 142/294/3 83/266/3 135/268/3
-f 74/407/3 73/211/3 126/270/3
-f 128/420/3 126/270/3 137/271/3
-f 143/285/2 138/272/2 139/274/2
-f 139/421/5 136/275/5 85/217/5
-f 129/422/1 128/276/1 133/278/1
-f 145/423/1 135/279/1 88/281/1
-f 133/278/1 137/277/1 141/283/1
-f 125/293/2 142/284/2 143/285/2
-f 136/269/3 138/286/3 137/271/3
-f 85/410/3 116/234/3 139/289/3
-f 133/264/3 141/290/3 134/265/3
-f 84/424/2 83/292/2 125/293/2
-f 145/423/1 141/283/1 135/279/1
-f 138/286/7 142/294/7 140/287/7
-f 116/234/3 119/242/3 143/288/3
-f 141/290/3 145/296/3 144/291/3
-f 147/299/2 157/425/2 156/426/2
-f 156/426/2 159/427/2 147/299/2
-f 170/428/2 146/297/2 147/299/2
-f 96/401/2 94/298/2 146/297/2
-f 147/299/2 159/427/2 170/428/2
-f 147/429/4 94/185/4 148/300/4
-f 171/350/3 86/188/3 146/301/3
-f 148/304/5 198/430/5 149/302/5
-f 149/302/5 155/431/5 147/303/5
-f 157/432/5 147/303/5 155/431/5
-f 79/433/5 80/305/5 152/307/5
-f 198/434/3 79/308/3 149/310/3
-f 152/307/5 151/306/5 154/312/5
-f 149/310/3 152/309/3 155/314/3
-f 155/314/3 154/313/3 157/316/3
-f 154/313/3 158/317/3 156/315/3
-f 167/347/3 77/208/3 160/319/3
-f 80/435/3 81/320/3 151/322/3
-f 153/436/3 151/322/3 162/323/3
-f 168/337/1 163/324/1 164/326/1
-f 164/437/6 161/327/6 87/329/6
-f 154/438/2 153/330/2 158/332/2
-f 171/346/2 160/333/2 86/223/2
-f 158/332/2 162/331/2 166/335/2
-f 150/345/1 167/336/1 168/337/1
-f 161/321/3 163/338/3 162/323/3
-f 87/439/3 169/340/3 164/342/3
-f 158/317/3 166/343/3 159/318/3
-f 76/411/1 77/238/1 150/345/1
-f 166/335/2 165/334/2 171/346/2
-f 163/338/3 167/347/3 165/339/3
-f 169/340/3 172/348/3 168/341/3
-f 166/343/3 171/350/3 170/344/3
-f 175/353/1 184/440/1 173/351/1
-f 173/351/1 176/441/1 195/442/1
-f 123/416/1 176/441/1 121/245/1
-f 195/442/1 174/352/1 173/351/1
-f 121/245/1 176/441/1 173/351/1
-f 173/443/4 148/300/4 121/247/4
-f 196/397/3 176/354/3 88/248/3
-f 178/357/5 198/430/5 148/304/5
-f 148/304/5 173/355/5 178/357/5
-f 184/444/5 177/356/5 173/355/5
-f 79/433/5 180/358/5 80/305/5
-f 198/434/3 178/360/3 79/308/3
-f 180/358/5 182/362/5 181/359/5
-f 178/360/3 177/364/3 180/361/3
-f 177/364/3 184/366/3 182/365/3
-f 182/365/3 175/367/3 185/369/3
-f 194/395/3 186/370/3 83/266/3
-f 80/435/3 181/371/3 81/320/3
-f 187/372/3 181/371/3 188/374/3
-f 193/385/2 189/375/2 190/377/2
-f 189/445/6 87/329/6 187/378/6
-f 182/446/1 185/379/1 183/381/1
-f 196/394/1 88/281/1 186/382/1
-f 185/379/1 191/383/1 188/380/1
-f 179/393/2 193/385/2 194/386/2
-f 187/372/3 188/374/3 190/388/3
-f 87/439/3 189/389/3 169/340/3
-f 185/369/3 174/368/3 191/392/3
-f 84/424/2 179/393/2 83/292/2
-f 191/383/1 196/394/1 192/384/1
-f 190/388/3 192/387/3 194/395/3
-f 169/340/3 193/390/3 172/348/3
-f 191/392/3 195/391/3 196/397/3
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Anzeige
-usemtl Anzeige
-f 99/447/3 76/448/3 100/449/3
-f 100/449/3 84/450/3 125/451/3
-f 100/449/3 76/448/3 150/452/3
-f 179/453/3 84/450/3 100/449/3
-f 119/454/3 99/447/3 100/449/3
-f 119/454/3 100/449/3 125/451/3
-f 172/455/3 100/449/3 150/452/3
-f 172/455/3 179/453/3 100/449/3
+f 103/404/6 97/190/6 89/189/6
+f 75/405/6 99/192/6 74/194/6
+f 196/406/3 98/195/3 75/197/3
+f 99/192/6 101/198/6 100/193/6
+f 98/195/3 97/200/3 99/196/3
+f 97/200/3 103/202/3 101/201/3
+f 101/201/3 91/203/3 104/205/3
+f 113/240/3 105/206/3 77/208/3
+f 74/407/3 100/209/3 73/211/3
+f 106/210/3 100/209/3 107/213/3
+f 112/228/1 108/214/1 109/216/1
+f 108/408/5 85/217/5 106/219/5
+f 101/409/2 104/220/2 102/222/2
+f 117/239/2 86/223/2 105/225/2
+f 104/220/2 110/226/2 107/221/2
+f 116/237/1 112/228/1 113/229/1
+f 106/210/3 107/213/3 109/231/3
+f 85/410/3 108/232/3 114/234/3
+f 104/205/3 90/204/3 110/236/3
+f 76/411/1 116/237/1 77/238/1
+f 111/227/2 110/226/2 105/225/2
+f 109/231/7 111/230/7 113/240/7
+f 114/234/3 112/233/3 118/242/3
+f 110/236/3 115/235/3 117/243/3
+f 121/246/1 130/412/1 129/413/1
+f 129/413/1 132/414/1 121/246/1
+f 142/415/1 119/244/1 121/246/1
+f 122/416/1 120/245/1 119/244/1
+f 121/246/1 132/414/1 142/415/1
+f 121/417/4 120/247/4 92/183/4
+f 144/296/3 88/248/3 119/250/3
+f 92/253/6 196/403/6 123/251/6
+f 123/251/6 128/418/6 121/252/6
+f 130/419/6 121/252/6 128/418/6
+f 75/405/6 74/194/6 125/255/6
+f 196/406/3 75/197/3 123/257/3
+f 125/255/6 124/254/6 127/259/6
+f 123/257/3 125/256/3 128/261/3
+f 128/261/3 127/260/3 130/263/3
+f 127/260/3 131/264/3 129/262/3
+f 140/294/3 83/266/3 133/268/3
+f 74/407/3 73/211/3 124/270/3
+f 126/420/3 124/270/3 135/271/3
+f 141/285/2 136/272/2 137/274/2
+f 137/421/5 134/275/5 85/217/5
+f 127/422/1 126/276/1 131/278/1
+f 144/423/1 133/279/1 88/281/1
+f 131/278/1 135/277/1 139/283/1
+f 143/293/2 140/284/2 141/285/2
+f 134/269/3 136/286/3 135/271/3
+f 85/410/3 114/234/3 137/289/3
+f 131/264/3 139/290/3 132/265/3
+f 84/424/2 83/292/2 143/293/2
+f 144/423/1 139/283/1 133/279/1
+f 136/286/7 140/294/7 138/287/7
+f 114/234/3 118/242/3 141/288/3
+f 139/290/3 144/296/3 142/291/3
+f 146/299/2 155/425/2 154/426/2
+f 154/426/2 157/427/2 146/299/2
+f 168/428/2 145/297/2 146/299/2
+f 96/401/2 94/298/2 145/297/2
+f 146/299/2 157/427/2 168/428/2
+f 146/429/4 94/185/4 147/300/4
+f 170/350/3 86/188/3 145/301/3
+f 147/304/5 197/430/5 148/302/5
+f 148/302/5 153/431/5 146/303/5
+f 155/432/5 146/303/5 153/431/5
+f 79/433/5 80/305/5 150/307/5
+f 197/434/3 79/308/3 148/310/3
+f 150/307/5 149/306/5 152/312/5
+f 148/310/3 150/309/3 153/314/3
+f 153/314/3 152/313/3 155/316/3
+f 152/313/3 156/317/3 154/315/3
+f 165/347/3 77/208/3 158/319/3
+f 80/435/3 81/320/3 149/322/3
+f 151/436/3 149/322/3 160/323/3
+f 166/337/1 161/324/1 162/326/1
+f 162/437/6 159/327/6 87/329/6
+f 152/438/2 151/330/2 156/332/2
+f 170/346/2 158/333/2 86/223/2
+f 156/332/2 160/331/2 164/335/2
+f 169/345/1 165/336/1 166/337/1
+f 159/321/3 161/338/3 160/323/3
+f 87/439/3 167/340/3 162/342/3
+f 156/317/3 164/343/3 157/318/3
+f 76/411/1 77/238/1 169/345/1
+f 164/335/2 163/334/2 170/346/2
+f 161/338/3 165/347/3 163/339/3
+f 167/340/3 171/348/3 166/341/3
+f 164/343/3 170/350/3 168/344/3
+f 174/353/1 182/440/1 172/351/1
+f 172/351/1 175/441/1 193/442/1
+f 122/416/1 175/441/1 120/245/1
+f 193/442/1 173/352/1 172/351/1
+f 120/245/1 175/441/1 172/351/1
+f 172/443/4 147/300/4 120/247/4
+f 195/397/3 175/354/3 88/248/3
+f 177/357/5 197/430/5 147/304/5
+f 147/304/5 172/355/5 177/357/5
+f 182/444/5 176/356/5 172/355/5
+f 79/433/5 178/358/5 80/305/5
+f 197/434/3 177/360/3 79/308/3
+f 178/358/5 180/362/5 179/359/5
+f 177/360/3 176/364/3 178/361/3
+f 176/364/3 182/366/3 180/365/3
+f 180/365/3 174/367/3 183/369/3
+f 192/395/3 184/370/3 83/266/3
+f 80/435/3 179/371/3 81/320/3
+f 185/372/3 179/371/3 186/374/3
+f 191/385/2 187/375/2 188/377/2
+f 187/445/6 87/329/6 185/378/6
+f 180/446/1 183/379/1 181/381/1
+f 195/394/1 88/281/1 184/382/1
+f 183/379/1 189/383/1 186/380/1
+f 194/393/2 191/385/2 192/386/2
+f 185/372/3 186/374/3 188/388/3
+f 87/439/3 187/389/3 167/340/3
+f 183/369/3 173/368/3 189/392/3
+f 84/424/2 194/393/2 83/292/2
+f 189/383/1 195/394/1 190/384/1
+f 188/388/3 190/387/3 192/395/3
+f 167/340/3 191/390/3 171/348/3
+f 189/392/3 193/391/3 195/397/3
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Anzeige.009
+usemtl Anzeige.009
+f 116/447/3 76/448/3 198/449/3
+f 198/449/3 84/450/3 143/451/3
+f 198/449/3 76/448/3 169/452/3
+f 194/453/3 84/450/3 198/449/3
+f 118/454/3 116/447/3 198/449/3
+f 118/454/3 198/449/3 143/451/3
+f 171/455/3 198/449/3 169/452/3
+f 171/455/3 194/453/3 198/449/3
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr45.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr45.obj
index f548ad3..046a963 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr45.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr45.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_bottom_smr45.mtl
-o HsVsAnzUnten_Cube.009
+o HsVsAnzUnten_Cube.008
v 0.290642 -0.495697 -0.331062
v 0.290642 -0.291434 -0.331062
v 0.331062 -0.291434 -0.371482
@@ -100,8 +100,6 @@ v 0.480413 0.431511 -0.284897
v 0.480413 0.319382 -0.284897
v 0.463865 0.483868 -0.301445
v 0.458595 0.483868 -0.306715
-v 0.458595 0.431511 -0.306715
-v 0.382655 0.319382 -0.382655
v 0.458595 0.465184 -0.306715
v 0.498517 0.465184 -0.346638
v 0.463865 0.465184 -0.301445
@@ -119,6 +117,7 @@ v 0.458595 0.449042 -0.306715
v 0.476480 0.431511 -0.324601
v 0.382655 0.449042 -0.382655
v 0.480413 0.449042 -0.284897
+v 0.458595 0.431511 -0.306715
v 0.463865 0.431511 -0.301445
v 0.382655 0.431511 -0.382655
v 0.284897 0.431511 -0.480413
@@ -126,7 +125,6 @@ v 0.216460 0.319382 -0.411976
v 0.216460 0.483868 -0.411976
v 0.284897 0.319382 -0.480413
v 0.306715 0.483868 -0.458595
-v 0.306715 0.431511 -0.458595
v 0.346638 0.465184 -0.498517
v 0.306715 0.465184 -0.458595
v 0.341368 0.465184 -0.503787
@@ -146,12 +144,12 @@ v 0.301445 0.449042 -0.463865
v 0.324601 0.431511 -0.476480
v 0.306715 0.449042 -0.458595
v 0.284897 0.449042 -0.480413
+v 0.306715 0.431511 -0.458595
v 0.301445 0.431511 -0.463865
v 0.480413 0.207254 -0.284897
v 0.411976 0.154897 -0.216460
v 0.314218 0.154897 -0.314218
v 0.458595 0.154897 -0.306715
-v 0.458595 0.207254 -0.306715
v 0.476480 0.173581 -0.324601
v 0.458595 0.173581 -0.306715
v 0.481750 0.173581 -0.319331
@@ -172,6 +170,7 @@ v 0.476480 0.207254 -0.324601
v 0.458595 0.189722 -0.306715
v 0.382655 0.189722 -0.382655
v 0.480413 0.189722 -0.284897
+v 0.458595 0.207254 -0.306715
v 0.463865 0.207254 -0.301445
v 0.382655 0.207254 -0.382655
v 0.216460 0.154897 -0.411976
@@ -180,7 +179,6 @@ v 0.284897 0.173581 -0.480413
v 0.284897 0.207254 -0.480413
v 0.301445 0.154897 -0.463865
v 0.306715 0.154897 -0.458595
-v 0.306715 0.207254 -0.458595
v 0.306715 0.173581 -0.458595
v 0.324601 0.173581 -0.476480
v 0.301445 0.173581 -0.463865
@@ -197,9 +195,11 @@ v 0.319331 0.189722 -0.481750
v 0.306715 0.189722 -0.458595
v 0.324601 0.207254 -0.476480
v 0.284897 0.189722 -0.480413
+v 0.306715 0.207254 -0.458595
v 0.301445 0.207254 -0.463865
v 0.382655 0.483868 -0.382655
v 0.382655 0.154897 -0.382655
+v 0.382655 0.319382 -0.382655
vt 0.646743 0.371805
vt 0.646743 0.142471
vt 0.705619 0.142471
@@ -646,15 +646,15 @@ vt 0.338275 0.011173
vt 0.315869 0.863702
vt 0.788504 0.988827
vt 0.743017 0.396107
-vt 0.000000 0.999918
-vt 0.000043 0.876332
-vt 0.118412 0.876373
-vt 0.236780 0.876414
-vt 0.236738 1.000000
-vt 0.000085 0.752745
-vt 0.236823 0.752827
-vt 0.118369 0.999959
-vt 0.118454 0.752786
+vt 0.003906 1.015625
+vt 0.003906 0.496094
+vt 0.500000 0.496094
+vt 1.000000 0.500000
+vt 1.000000 1.015625
+vt 0.003906 -0.019531
+vt 1.000000 -0.019531
+vt 0.500000 1.015625
+vt 0.500000 -0.019531
vn -0.7071 0.0000 -0.7071
vn 0.7071 0.0000 0.7071
vn 0.7071 0.0000 -0.7071
@@ -662,8 +662,8 @@ vn -0.7071 0.0000 0.7071
vn 0.0000 -1.0000 -0.0000
vn 0.0000 1.0000 0.0000
vn 0.3467 -0.8716 -0.3467
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Mast
-usemtl Mast
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Mast.009
+usemtl Mast.009
s 1
f 1/1/1 2/2/1 3/3/1
f 2/2/1 4/4/1 5/5/1
@@ -791,255 +791,255 @@ f 85/176/2 73/135/2 75/137/2
f 86/177/5 76/138/5 78/140/5
f 87/178/2 79/141/2 81/143/2
f 88/179/5 82/144/5 84/146/5
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Schirm
-usemtl Schirm
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Schirm.009
+usemtl Schirm.009
f 89/180/2 90/181/2 91/182/2
f 92/183/4 93/184/4 94/185/4
f 95/186/3 96/187/3 86/188/3
f 89/189/6 97/190/6 98/191/6
-f 101/192/6 102/193/6 74/194/6
-f 98/195/3 101/196/3 75/197/3
-f 103/198/6 104/199/6 102/193/6
-f 97/200/3 103/201/3 101/196/3
-f 105/202/3 91/203/3 103/201/3
-f 91/203/3 90/204/3 106/205/3
-f 107/206/3 78/207/3 77/208/3
-f 102/209/3 108/210/3 73/211/3
-f 102/209/3 104/212/3 109/213/3
-f 110/214/1 108/215/1 111/216/1
-f 85/217/5 73/218/5 108/219/5
-f 106/220/2 109/221/2 104/222/2
-f 86/223/2 78/224/2 107/225/2
-f 112/226/2 113/227/2 109/221/2
-f 114/228/1 111/216/1 115/229/1
-f 109/213/3 113/230/3 111/231/3
-f 110/232/3 114/233/3 116/234/3
-f 90/204/3 117/235/3 112/236/3
-f 99/237/1 115/229/1 77/238/1
-f 112/226/2 118/239/2 107/225/2
-f 113/230/7 107/206/7 115/240/7
-f 114/233/3 99/241/3 119/242/3
-f 117/235/3 95/186/3 118/243/3
-f 120/244/1 121/245/1 122/246/1
-f 121/247/4 93/184/4 92/183/4
-f 88/248/3 123/249/3 120/250/3
-f 124/251/6 122/252/6 92/253/6
-f 74/194/6 126/254/6 127/255/6
-f 75/197/3 127/256/3 124/257/3
-f 126/254/6 128/258/6 129/259/6
-f 127/256/3 129/260/3 130/261/3
-f 129/260/3 131/262/3 132/263/3
-f 133/264/3 134/265/3 131/262/3
-f 83/266/3 82/267/3 135/268/3
-f 73/211/3 136/269/3 126/270/3
-f 126/270/3 136/269/3 137/271/3
-f 138/272/2 136/273/2 139/274/2
-f 136/275/5 73/218/5 85/217/5
-f 128/276/1 137/277/1 133/278/1
-f 135/279/1 82/280/1 88/281/1
-f 137/277/1 140/282/1 141/283/1
-f 142/284/2 138/272/2 143/285/2
-f 138/286/3 140/287/3 137/271/3
-f 116/234/3 143/288/3 139/289/3
-f 141/290/3 144/291/3 134/265/3
-f 83/292/2 142/284/2 125/293/2
-f 141/283/1 140/282/1 135/279/1
-f 142/294/7 135/268/7 140/287/7
-f 119/242/3 125/295/3 143/288/3
-f 145/296/3 120/250/3 144/291/3
-f 146/297/2 94/298/2 147/299/2
-f 94/185/4 93/184/4 148/300/4
-f 86/188/3 96/187/3 146/301/3
-f 149/302/5 147/303/5 148/304/5
-f 80/305/5 151/306/5 152/307/5
-f 79/308/3 152/309/3 149/310/3
-f 151/306/5 153/311/5 154/312/5
-f 152/309/3 154/313/3 155/314/3
-f 154/313/3 156/315/3 157/316/3
-f 158/317/3 159/318/3 156/315/3
-f 77/208/3 78/207/3 160/319/3
-f 81/320/3 161/321/3 151/322/3
-f 151/322/3 161/321/3 162/323/3
-f 163/324/1 161/325/1 164/326/1
-f 161/327/6 81/328/6 87/329/6
-f 153/330/2 162/331/2 158/332/2
-f 160/333/2 78/224/2 86/223/2
-f 162/331/2 165/334/2 166/335/2
-f 167/336/1 163/324/1 168/337/1
-f 163/338/3 165/339/3 162/323/3
-f 169/340/3 168/341/3 164/342/3
-f 166/343/3 170/344/3 159/318/3
-f 77/238/1 167/336/1 150/345/1
-f 165/334/2 160/333/2 171/346/2
-f 167/347/3 160/319/3 165/339/3
-f 172/348/3 150/349/3 168/341/3
-f 171/350/3 146/301/3 170/344/3
-f 173/351/1 174/352/1 175/353/1
-f 148/300/4 93/184/4 121/247/4
-f 176/354/3 123/249/3 88/248/3
-f 173/355/5 177/356/5 178/357/5
-f 180/358/5 181/359/5 80/305/5
-f 178/360/3 180/361/3 79/308/3
-f 182/362/5 183/363/5 181/359/5
-f 177/364/3 182/365/3 180/361/3
-f 184/366/3 175/367/3 182/365/3
-f 175/367/3 174/368/3 185/369/3
-f 186/370/3 82/267/3 83/266/3
-f 181/371/3 187/372/3 81/320/3
-f 181/371/3 183/373/3 188/374/3
-f 189/375/2 187/376/2 190/377/2
-f 87/329/6 81/328/6 187/378/6
-f 185/379/1 188/380/1 183/381/1
-f 88/281/1 82/280/1 186/382/1
-f 191/383/1 192/384/1 188/380/1
-f 193/385/2 190/377/2 194/386/2
-f 188/374/3 192/387/3 190/388/3
-f 189/389/3 193/390/3 169/340/3
-f 174/368/3 195/391/3 191/392/3
-f 179/393/2 194/386/2 83/292/2
-f 196/394/1 186/382/1 192/384/1
-f 192/387/3 186/370/3 194/395/3
-f 193/390/3 179/396/3 172/348/3
-f 195/391/3 176/354/3 196/397/3
-f 91/182/2 105/398/2 89/180/2
-f 89/180/2 95/399/2 117/400/2
+f 99/192/6 100/193/6 74/194/6
+f 98/195/3 99/196/3 75/197/3
+f 101/198/6 102/199/6 100/193/6
+f 97/200/3 101/201/3 99/196/3
+f 103/202/3 91/203/3 101/201/3
+f 91/203/3 90/204/3 104/205/3
+f 105/206/3 78/207/3 77/208/3
+f 100/209/3 106/210/3 73/211/3
+f 100/209/3 102/212/3 107/213/3
+f 108/214/1 106/215/1 109/216/1
+f 85/217/5 73/218/5 106/219/5
+f 104/220/2 107/221/2 102/222/2
+f 86/223/2 78/224/2 105/225/2
+f 110/226/2 111/227/2 107/221/2
+f 112/228/1 109/216/1 113/229/1
+f 107/213/3 111/230/3 109/231/3
+f 108/232/3 112/233/3 114/234/3
+f 90/204/3 115/235/3 110/236/3
+f 116/237/1 113/229/1 77/238/1
+f 110/226/2 117/239/2 105/225/2
+f 111/230/7 105/206/7 113/240/7
+f 112/233/3 116/241/3 118/242/3
+f 115/235/3 95/186/3 117/243/3
+f 119/244/1 120/245/1 121/246/1
+f 120/247/4 93/184/4 92/183/4
+f 88/248/3 122/249/3 119/250/3
+f 123/251/6 121/252/6 92/253/6
+f 74/194/6 124/254/6 125/255/6
+f 75/197/3 125/256/3 123/257/3
+f 124/254/6 126/258/6 127/259/6
+f 125/256/3 127/260/3 128/261/3
+f 127/260/3 129/262/3 130/263/3
+f 131/264/3 132/265/3 129/262/3
+f 83/266/3 82/267/3 133/268/3
+f 73/211/3 134/269/3 124/270/3
+f 124/270/3 134/269/3 135/271/3
+f 136/272/2 134/273/2 137/274/2
+f 134/275/5 73/218/5 85/217/5
+f 126/276/1 135/277/1 131/278/1
+f 133/279/1 82/280/1 88/281/1
+f 135/277/1 138/282/1 139/283/1
+f 140/284/2 136/272/2 141/285/2
+f 136/286/3 138/287/3 135/271/3
+f 114/234/3 141/288/3 137/289/3
+f 139/290/3 142/291/3 132/265/3
+f 83/292/2 140/284/2 143/293/2
+f 139/283/1 138/282/1 133/279/1
+f 140/294/7 133/268/7 138/287/7
+f 118/242/3 143/295/3 141/288/3
+f 144/296/3 119/250/3 142/291/3
+f 145/297/2 94/298/2 146/299/2
+f 94/185/4 93/184/4 147/300/4
+f 86/188/3 96/187/3 145/301/3
+f 148/302/5 146/303/5 147/304/5
+f 80/305/5 149/306/5 150/307/5
+f 79/308/3 150/309/3 148/310/3
+f 149/306/5 151/311/5 152/312/5
+f 150/309/3 152/313/3 153/314/3
+f 152/313/3 154/315/3 155/316/3
+f 156/317/3 157/318/3 154/315/3
+f 77/208/3 78/207/3 158/319/3
+f 81/320/3 159/321/3 149/322/3
+f 149/322/3 159/321/3 160/323/3
+f 161/324/1 159/325/1 162/326/1
+f 159/327/6 81/328/6 87/329/6
+f 151/330/2 160/331/2 156/332/2
+f 158/333/2 78/224/2 86/223/2
+f 160/331/2 163/334/2 164/335/2
+f 165/336/1 161/324/1 166/337/1
+f 161/338/3 163/339/3 160/323/3
+f 167/340/3 166/341/3 162/342/3
+f 164/343/3 168/344/3 157/318/3
+f 77/238/1 165/336/1 169/345/1
+f 163/334/2 158/333/2 170/346/2
+f 165/347/3 158/319/3 163/339/3
+f 171/348/3 169/349/3 166/341/3
+f 170/350/3 145/301/3 168/344/3
+f 172/351/1 173/352/1 174/353/1
+f 147/300/4 93/184/4 120/247/4
+f 175/354/3 122/249/3 88/248/3
+f 172/355/5 176/356/5 177/357/5
+f 178/358/5 179/359/5 80/305/5
+f 177/360/3 178/361/3 79/308/3
+f 180/362/5 181/363/5 179/359/5
+f 176/364/3 180/365/3 178/361/3
+f 182/366/3 174/367/3 180/365/3
+f 174/367/3 173/368/3 183/369/3
+f 184/370/3 82/267/3 83/266/3
+f 179/371/3 185/372/3 81/320/3
+f 179/371/3 181/373/3 186/374/3
+f 187/375/2 185/376/2 188/377/2
+f 87/329/6 81/328/6 185/378/6
+f 183/379/1 186/380/1 181/381/1
+f 88/281/1 82/280/1 184/382/1
+f 189/383/1 190/384/1 186/380/1
+f 191/385/2 188/377/2 192/386/2
+f 186/374/3 190/387/3 188/388/3
+f 187/389/3 191/390/3 167/340/3
+f 173/368/3 193/391/3 189/392/3
+f 194/393/2 192/386/2 83/292/2
+f 195/394/1 184/382/1 190/384/1
+f 190/387/3 184/370/3 192/395/3
+f 191/390/3 194/396/3 171/348/3
+f 193/391/3 175/354/3 195/397/3
+f 91/182/2 103/398/2 89/180/2
+f 89/180/2 95/399/2 115/400/2
f 96/401/2 95/399/2 94/298/2
-f 117/400/2 90/181/2 89/180/2
+f 115/400/2 90/181/2 89/180/2
f 94/298/2 95/399/2 89/180/2
f 89/402/4 92/183/4 94/185/4
-f 118/243/3 95/186/3 86/188/3
-f 98/191/6 197/403/6 92/253/6
+f 117/243/3 95/186/3 86/188/3
+f 98/191/6 196/403/6 92/253/6
f 92/253/6 89/189/6 98/191/6
-f 105/404/6 97/190/6 89/189/6
-f 75/405/6 101/192/6 74/194/6
-f 197/406/3 98/195/3 75/197/3
-f 101/192/6 103/198/6 102/193/6
-f 98/195/3 97/200/3 101/196/3
-f 97/200/3 105/202/3 103/201/3
-f 103/201/3 91/203/3 106/205/3
-f 115/240/3 107/206/3 77/208/3
-f 74/407/3 102/209/3 73/211/3
-f 108/210/3 102/209/3 109/213/3
-f 114/228/1 110/214/1 111/216/1
-f 110/408/5 85/217/5 108/219/5
-f 103/409/2 106/220/2 104/222/2
-f 118/239/2 86/223/2 107/225/2
-f 106/220/2 112/226/2 109/221/2
-f 99/237/1 114/228/1 115/229/1
-f 108/210/3 109/213/3 111/231/3
-f 85/410/3 110/232/3 116/234/3
-f 106/205/3 90/204/3 112/236/3
-f 76/411/1 99/237/1 77/238/1
-f 113/227/2 112/226/2 107/225/2
-f 111/231/7 113/230/7 115/240/7
-f 116/234/3 114/233/3 119/242/3
-f 112/236/3 117/235/3 118/243/3
-f 122/246/1 132/412/1 131/413/1
-f 131/413/1 134/414/1 122/246/1
-f 144/415/1 120/244/1 122/246/1
-f 123/416/1 121/245/1 120/244/1
-f 122/246/1 134/414/1 144/415/1
-f 122/417/4 121/247/4 92/183/4
-f 145/296/3 88/248/3 120/250/3
-f 92/253/6 197/403/6 124/251/6
-f 124/251/6 130/418/6 122/252/6
-f 132/419/6 122/252/6 130/418/6
-f 75/405/6 74/194/6 127/255/6
-f 197/406/3 75/197/3 124/257/3
-f 127/255/6 126/254/6 129/259/6
-f 124/257/3 127/256/3 130/261/3
-f 130/261/3 129/260/3 132/263/3
-f 129/260/3 133/264/3 131/262/3
-f 142/294/3 83/266/3 135/268/3
-f 74/407/3 73/211/3 126/270/3
-f 128/420/3 126/270/3 137/271/3
-f 143/285/2 138/272/2 139/274/2
-f 139/421/5 136/275/5 85/217/5
-f 129/422/1 128/276/1 133/278/1
-f 145/423/1 135/279/1 88/281/1
-f 133/278/1 137/277/1 141/283/1
-f 125/293/2 142/284/2 143/285/2
-f 136/269/3 138/286/3 137/271/3
-f 85/410/3 116/234/3 139/289/3
-f 133/264/3 141/290/3 134/265/3
-f 84/424/2 83/292/2 125/293/2
-f 145/423/1 141/283/1 135/279/1
-f 138/286/7 142/294/7 140/287/7
-f 116/234/3 119/242/3 143/288/3
-f 141/290/3 145/296/3 144/291/3
-f 147/299/2 157/425/2 156/426/2
-f 156/426/2 159/427/2 147/299/2
-f 170/428/2 146/297/2 147/299/2
-f 96/401/2 94/298/2 146/297/2
-f 147/299/2 159/427/2 170/428/2
-f 147/429/4 94/185/4 148/300/4
-f 171/350/3 86/188/3 146/301/3
-f 148/304/5 198/430/5 149/302/5
-f 149/302/5 155/431/5 147/303/5
-f 157/432/5 147/303/5 155/431/5
-f 79/433/5 80/305/5 152/307/5
-f 198/434/3 79/308/3 149/310/3
-f 152/307/5 151/306/5 154/312/5
-f 149/310/3 152/309/3 155/314/3
-f 155/314/3 154/313/3 157/316/3
-f 154/313/3 158/317/3 156/315/3
-f 167/347/3 77/208/3 160/319/3
-f 80/435/3 81/320/3 151/322/3
-f 153/436/3 151/322/3 162/323/3
-f 168/337/1 163/324/1 164/326/1
-f 164/437/6 161/327/6 87/329/6
-f 154/438/2 153/330/2 158/332/2
-f 171/346/2 160/333/2 86/223/2
-f 158/332/2 162/331/2 166/335/2
-f 150/345/1 167/336/1 168/337/1
-f 161/321/3 163/338/3 162/323/3
-f 87/439/3 169/340/3 164/342/3
-f 158/317/3 166/343/3 159/318/3
-f 76/411/1 77/238/1 150/345/1
-f 166/335/2 165/334/2 171/346/2
-f 163/338/3 167/347/3 165/339/3
-f 169/340/3 172/348/3 168/341/3
-f 166/343/3 171/350/3 170/344/3
-f 175/353/1 184/440/1 173/351/1
-f 173/351/1 176/441/1 195/442/1
-f 123/416/1 176/441/1 121/245/1
-f 195/442/1 174/352/1 173/351/1
-f 121/245/1 176/441/1 173/351/1
-f 173/443/4 148/300/4 121/247/4
-f 196/397/3 176/354/3 88/248/3
-f 178/357/5 198/430/5 148/304/5
-f 148/304/5 173/355/5 178/357/5
-f 184/444/5 177/356/5 173/355/5
-f 79/433/5 180/358/5 80/305/5
-f 198/434/3 178/360/3 79/308/3
-f 180/358/5 182/362/5 181/359/5
-f 178/360/3 177/364/3 180/361/3
-f 177/364/3 184/366/3 182/365/3
-f 182/365/3 175/367/3 185/369/3
-f 194/395/3 186/370/3 83/266/3
-f 80/435/3 181/371/3 81/320/3
-f 187/372/3 181/371/3 188/374/3
-f 193/385/2 189/375/2 190/377/2
-f 189/445/6 87/329/6 187/378/6
-f 182/446/1 185/379/1 183/381/1
-f 196/394/1 88/281/1 186/382/1
-f 185/379/1 191/383/1 188/380/1
-f 179/393/2 193/385/2 194/386/2
-f 187/372/3 188/374/3 190/388/3
-f 87/439/3 189/389/3 169/340/3
-f 185/369/3 174/368/3 191/392/3
-f 84/424/2 179/393/2 83/292/2
-f 191/383/1 196/394/1 192/384/1
-f 190/388/3 192/387/3 194/395/3
-f 169/340/3 193/390/3 172/348/3
-f 191/392/3 195/391/3 196/397/3
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Anzeige
-usemtl Anzeige
-f 99/447/3 76/448/3 100/449/3
-f 100/449/3 84/450/3 125/451/3
-f 100/449/3 76/448/3 150/452/3
-f 179/453/3 84/450/3 100/449/3
-f 119/454/3 99/447/3 100/449/3
-f 119/454/3 100/449/3 125/451/3
-f 172/455/3 100/449/3 150/452/3
-f 172/455/3 179/453/3 100/449/3
+f 103/404/6 97/190/6 89/189/6
+f 75/405/6 99/192/6 74/194/6
+f 196/406/3 98/195/3 75/197/3
+f 99/192/6 101/198/6 100/193/6
+f 98/195/3 97/200/3 99/196/3
+f 97/200/3 103/202/3 101/201/3
+f 101/201/3 91/203/3 104/205/3
+f 113/240/3 105/206/3 77/208/3
+f 74/407/3 100/209/3 73/211/3
+f 106/210/3 100/209/3 107/213/3
+f 112/228/1 108/214/1 109/216/1
+f 108/408/5 85/217/5 106/219/5
+f 101/409/2 104/220/2 102/222/2
+f 117/239/2 86/223/2 105/225/2
+f 104/220/2 110/226/2 107/221/2
+f 116/237/1 112/228/1 113/229/1
+f 106/210/3 107/213/3 109/231/3
+f 85/410/3 108/232/3 114/234/3
+f 104/205/3 90/204/3 110/236/3
+f 76/411/1 116/237/1 77/238/1
+f 111/227/2 110/226/2 105/225/2
+f 109/231/7 111/230/7 113/240/7
+f 114/234/3 112/233/3 118/242/3
+f 110/236/3 115/235/3 117/243/3
+f 121/246/1 130/412/1 129/413/1
+f 129/413/1 132/414/1 121/246/1
+f 142/415/1 119/244/1 121/246/1
+f 122/416/1 120/245/1 119/244/1
+f 121/246/1 132/414/1 142/415/1
+f 121/417/4 120/247/4 92/183/4
+f 144/296/3 88/248/3 119/250/3
+f 92/253/6 196/403/6 123/251/6
+f 123/251/6 128/418/6 121/252/6
+f 130/419/6 121/252/6 128/418/6
+f 75/405/6 74/194/6 125/255/6
+f 196/406/3 75/197/3 123/257/3
+f 125/255/6 124/254/6 127/259/6
+f 123/257/3 125/256/3 128/261/3
+f 128/261/3 127/260/3 130/263/3
+f 127/260/3 131/264/3 129/262/3
+f 140/294/3 83/266/3 133/268/3
+f 74/407/3 73/211/3 124/270/3
+f 126/420/3 124/270/3 135/271/3
+f 141/285/2 136/272/2 137/274/2
+f 137/421/5 134/275/5 85/217/5
+f 127/422/1 126/276/1 131/278/1
+f 144/423/1 133/279/1 88/281/1
+f 131/278/1 135/277/1 139/283/1
+f 143/293/2 140/284/2 141/285/2
+f 134/269/3 136/286/3 135/271/3
+f 85/410/3 114/234/3 137/289/3
+f 131/264/3 139/290/3 132/265/3
+f 84/424/2 83/292/2 143/293/2
+f 144/423/1 139/283/1 133/279/1
+f 136/286/7 140/294/7 138/287/7
+f 114/234/3 118/242/3 141/288/3
+f 139/290/3 144/296/3 142/291/3
+f 146/299/2 155/425/2 154/426/2
+f 154/426/2 157/427/2 146/299/2
+f 168/428/2 145/297/2 146/299/2
+f 96/401/2 94/298/2 145/297/2
+f 146/299/2 157/427/2 168/428/2
+f 146/429/4 94/185/4 147/300/4
+f 170/350/3 86/188/3 145/301/3
+f 147/304/5 197/430/5 148/302/5
+f 148/302/5 153/431/5 146/303/5
+f 155/432/5 146/303/5 153/431/5
+f 79/433/5 80/305/5 150/307/5
+f 197/434/3 79/308/3 148/310/3
+f 150/307/5 149/306/5 152/312/5
+f 148/310/3 150/309/3 153/314/3
+f 153/314/3 152/313/3 155/316/3
+f 152/313/3 156/317/3 154/315/3
+f 165/347/3 77/208/3 158/319/3
+f 80/435/3 81/320/3 149/322/3
+f 151/436/3 149/322/3 160/323/3
+f 166/337/1 161/324/1 162/326/1
+f 162/437/6 159/327/6 87/329/6
+f 152/438/2 151/330/2 156/332/2
+f 170/346/2 158/333/2 86/223/2
+f 156/332/2 160/331/2 164/335/2
+f 169/345/1 165/336/1 166/337/1
+f 159/321/3 161/338/3 160/323/3
+f 87/439/3 167/340/3 162/342/3
+f 156/317/3 164/343/3 157/318/3
+f 76/411/1 77/238/1 169/345/1
+f 164/335/2 163/334/2 170/346/2
+f 161/338/3 165/347/3 163/339/3
+f 167/340/3 171/348/3 166/341/3
+f 164/343/3 170/350/3 168/344/3
+f 174/353/1 182/440/1 172/351/1
+f 172/351/1 175/441/1 193/442/1
+f 122/416/1 175/441/1 120/245/1
+f 193/442/1 173/352/1 172/351/1
+f 120/245/1 175/441/1 172/351/1
+f 172/443/4 147/300/4 120/247/4
+f 195/397/3 175/354/3 88/248/3
+f 177/357/5 197/430/5 147/304/5
+f 147/304/5 172/355/5 177/357/5
+f 182/444/5 176/356/5 172/355/5
+f 79/433/5 178/358/5 80/305/5
+f 197/434/3 177/360/3 79/308/3
+f 178/358/5 180/362/5 179/359/5
+f 177/360/3 176/364/3 178/361/3
+f 176/364/3 182/366/3 180/365/3
+f 180/365/3 174/367/3 183/369/3
+f 192/395/3 184/370/3 83/266/3
+f 80/435/3 179/371/3 81/320/3
+f 185/372/3 179/371/3 186/374/3
+f 191/385/2 187/375/2 188/377/2
+f 187/445/6 87/329/6 185/378/6
+f 180/446/1 183/379/1 181/381/1
+f 195/394/1 88/281/1 184/382/1
+f 183/379/1 189/383/1 186/380/1
+f 194/393/2 191/385/2 192/386/2
+f 185/372/3 186/374/3 188/388/3
+f 87/439/3 187/389/3 167/340/3
+f 183/369/3 173/368/3 189/392/3
+f 84/424/2 194/393/2 83/292/2
+f 189/383/1 195/394/1 190/384/1
+f 188/388/3 190/387/3 192/395/3
+f 167/340/3 191/390/3 171/348/3
+f 189/392/3 193/391/3 195/397/3
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Anzeige.009
+usemtl Anzeige.009
+f 116/447/3 76/448/3 198/449/3
+f 198/449/3 84/450/3 143/451/3
+f 198/449/3 76/448/3 169/452/3
+f 194/453/3 84/450/3 198/449/3
+f 118/454/3 116/447/3 198/449/3
+f 118/454/3 198/449/3 143/451/3
+f 171/455/3 198/449/3 169/452/3
+f 171/455/3 194/453/3 198/449/3
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr60.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr60.obj
index 5a12ae5..28043dd 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr60.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_bottom_smr60.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_bottom_smr60.mtl
-o HsVsAnzUnten_Cube.009
+o HsVsAnzUnten_Cube.008
v 0.380670 -0.495697 -0.221732
v 0.380670 -0.291434 -0.221732
v 0.431827 -0.291434 -0.247238
@@ -100,8 +100,6 @@ v 0.545986 0.431511 -0.117737
v 0.545986 0.319382 -0.117737
v 0.535544 0.483868 -0.138681
v 0.532218 0.483868 -0.145351
-v 0.532218 0.431511 -0.145351
-v 0.484299 0.319382 -0.241463
v 0.532218 0.465184 -0.145351
v 0.582746 0.465184 -0.170543
v 0.535544 0.465184 -0.138681
@@ -119,6 +117,7 @@ v 0.532218 0.449042 -0.145351
v 0.554855 0.431511 -0.156637
v 0.484299 0.449042 -0.241463
v 0.545986 0.449042 -0.117737
+v 0.532218 0.431511 -0.145351
v 0.535544 0.431511 -0.138681
v 0.484299 0.431511 -0.241463
v 0.422612 0.431511 -0.365188
@@ -126,7 +125,6 @@ v 0.335996 0.319382 -0.322003
v 0.335996 0.483868 -0.322003
v 0.422612 0.319382 -0.365188
v 0.436380 0.483868 -0.337574
-v 0.436380 0.431511 -0.337574
v 0.486907 0.465184 -0.362766
v 0.436380 0.465184 -0.337574
v 0.483581 0.465184 -0.369436
@@ -146,12 +144,12 @@ v 0.433054 0.449042 -0.344244
v 0.459016 0.431511 -0.348860
v 0.436380 0.449042 -0.337574
v 0.422612 0.449042 -0.365188
+v 0.436380 0.431511 -0.337574
v 0.433054 0.431511 -0.344244
v 0.545986 0.207254 -0.117737
v 0.459370 0.154897 -0.074552
v 0.397683 0.154897 -0.198277
v 0.532219 0.154897 -0.145351
-v 0.532219 0.207254 -0.145351
v 0.554855 0.173581 -0.156637
v 0.532219 0.173581 -0.145351
v 0.558180 0.173581 -0.149967
@@ -172,6 +170,7 @@ v 0.554855 0.207254 -0.156637
v 0.532219 0.189722 -0.145351
v 0.484299 0.189722 -0.241463
v 0.545986 0.189722 -0.117737
+v 0.532219 0.207254 -0.145351
v 0.535544 0.207254 -0.138681
v 0.484299 0.207254 -0.241463
v 0.335996 0.154897 -0.322003
@@ -180,7 +179,6 @@ v 0.422612 0.173581 -0.365188
v 0.422612 0.207254 -0.365188
v 0.433054 0.154897 -0.344244
v 0.436380 0.154897 -0.337574
-v 0.436380 0.207254 -0.337574
v 0.436380 0.173581 -0.337574
v 0.459016 0.173581 -0.348860
v 0.433054 0.173581 -0.344244
@@ -197,9 +195,11 @@ v 0.455691 0.189722 -0.355530
v 0.436380 0.189722 -0.337574
v 0.459016 0.207254 -0.348860
v 0.422612 0.189722 -0.365188
+v 0.436380 0.207254 -0.337574
v 0.433054 0.207254 -0.344244
v 0.484299 0.483868 -0.241463
v 0.484299 0.154897 -0.241463
+v 0.484299 0.319382 -0.241463
vt 0.646743 0.371805
vt 0.646743 0.142471
vt 0.705619 0.142471
@@ -646,15 +646,15 @@ vt 0.338275 0.011173
vt 0.315869 0.863702
vt 0.788504 0.988827
vt 0.743017 0.396107
-vt 0.000000 0.999918
-vt 0.000043 0.876332
-vt 0.118412 0.876373
-vt 0.236780 0.876414
-vt 0.236738 1.000000
-vt 0.000085 0.752745
-vt 0.236823 0.752827
-vt 0.118369 0.999959
-vt 0.118454 0.752786
+vt 0.003906 1.015625
+vt 0.003906 0.496094
+vt 0.500000 0.496094
+vt 1.000000 0.500000
+vt 1.000000 1.015625
+vt 0.003906 -0.019531
+vt 1.000000 -0.019531
+vt 0.500000 1.015625
+vt 0.500000 -0.019531
vn -0.4462 0.0000 -0.8949
vn 0.4462 0.0000 0.8949
vn 0.8949 0.0000 -0.4462
@@ -662,8 +662,8 @@ vn -0.8949 0.0000 0.4462
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 0.4388 -0.8716 -0.2188
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Mast
-usemtl Mast
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Mast.009
+usemtl Mast.009
s 1
f 1/1/1 2/2/1 3/3/1
f 2/2/1 4/4/1 5/5/1
@@ -791,255 +791,255 @@ f 85/176/2 73/135/2 75/137/2
f 86/177/5 76/138/5 78/140/5
f 87/178/2 79/141/2 81/143/2
f 88/179/5 82/144/5 84/146/5
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Schirm
-usemtl Schirm
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Schirm.009
+usemtl Schirm.009
f 89/180/2 90/181/2 91/182/2
f 92/183/4 93/184/4 94/185/4
f 95/186/3 96/187/3 86/188/3
f 89/189/6 97/190/6 98/191/6
-f 101/192/6 102/193/6 74/194/6
-f 98/195/3 101/196/3 75/197/3
-f 103/198/6 104/199/6 102/193/6
-f 97/200/3 103/201/3 101/196/3
-f 105/202/3 91/203/3 103/201/3
-f 91/203/3 90/204/3 106/205/3
-f 107/206/3 78/207/3 77/208/3
-f 102/209/3 108/210/3 73/211/3
-f 102/209/3 104/212/3 109/213/3
-f 110/214/1 108/215/1 111/216/1
-f 85/217/5 73/218/5 108/219/5
-f 106/220/2 109/221/2 104/222/2
-f 86/223/2 78/224/2 107/225/2
-f 112/226/2 113/227/2 109/221/2
-f 114/228/1 111/216/1 115/229/1
-f 109/213/3 113/230/3 111/231/3
-f 110/232/3 114/233/3 116/234/3
-f 90/204/3 117/235/3 112/236/3
-f 99/237/1 115/229/1 77/238/1
-f 112/226/2 118/239/2 107/225/2
-f 113/230/7 107/206/7 115/240/7
-f 114/233/3 99/241/3 119/242/3
-f 117/235/3 95/186/3 118/243/3
-f 120/244/1 121/245/1 122/246/1
-f 121/247/4 93/184/4 92/183/4
-f 88/248/3 123/249/3 120/250/3
-f 124/251/6 122/252/6 92/253/6
-f 74/194/6 126/254/6 127/255/6
-f 75/197/3 127/256/3 124/257/3
-f 126/254/6 128/258/6 129/259/6
-f 127/256/3 129/260/3 130/261/3
-f 129/260/3 131/262/3 132/263/3
-f 133/264/3 134/265/3 131/262/3
-f 83/266/3 82/267/3 135/268/3
-f 73/211/3 136/269/3 126/270/3
-f 126/270/3 136/269/3 137/271/3
-f 138/272/2 136/273/2 139/274/2
-f 136/275/5 73/218/5 85/217/5
-f 128/276/1 137/277/1 133/278/1
-f 135/279/1 82/280/1 88/281/1
-f 137/277/1 140/282/1 141/283/1
-f 142/284/2 138/272/2 143/285/2
-f 138/286/3 140/287/3 137/271/3
-f 116/234/3 143/288/3 139/289/3
-f 141/290/3 144/291/3 134/265/3
-f 83/292/2 142/284/2 125/293/2
-f 141/283/1 140/282/1 135/279/1
-f 142/294/7 135/268/7 140/287/7
-f 119/242/3 125/295/3 143/288/3
-f 145/296/3 120/250/3 144/291/3
-f 146/297/2 94/298/2 147/299/2
-f 94/185/4 93/184/4 148/300/4
-f 86/188/3 96/187/3 146/301/3
-f 149/302/5 147/303/5 148/304/5
-f 80/305/5 151/306/5 152/307/5
-f 79/308/3 152/309/3 149/310/3
-f 151/306/5 153/311/5 154/312/5
-f 152/309/3 154/313/3 155/314/3
-f 154/313/3 156/315/3 157/316/3
-f 158/317/3 159/318/3 156/315/3
-f 77/208/3 78/207/3 160/319/3
-f 81/320/3 161/321/3 151/322/3
-f 151/322/3 161/321/3 162/323/3
-f 163/324/1 161/325/1 164/326/1
-f 161/327/6 81/328/6 87/329/6
-f 153/330/2 162/331/2 158/332/2
-f 160/333/2 78/224/2 86/223/2
-f 162/331/2 165/334/2 166/335/2
-f 167/336/1 163/324/1 168/337/1
-f 163/338/3 165/339/3 162/323/3
-f 169/340/3 168/341/3 164/342/3
-f 166/343/3 170/344/3 159/318/3
-f 77/238/1 167/336/1 150/345/1
-f 165/334/2 160/333/2 171/346/2
-f 167/347/3 160/319/3 165/339/3
-f 172/348/3 150/349/3 168/341/3
-f 171/350/3 146/301/3 170/344/3
-f 173/351/1 174/352/1 175/353/1
-f 148/300/4 93/184/4 121/247/4
-f 176/354/3 123/249/3 88/248/3
-f 173/355/5 177/356/5 178/357/5
-f 180/358/5 181/359/5 80/305/5
-f 178/360/3 180/361/3 79/308/3
-f 182/362/5 183/363/5 181/359/5
-f 177/364/3 182/365/3 180/361/3
-f 184/366/3 175/367/3 182/365/3
-f 175/367/3 174/368/3 185/369/3
-f 186/370/3 82/267/3 83/266/3
-f 181/371/3 187/372/3 81/320/3
-f 181/371/3 183/373/3 188/374/3
-f 189/375/2 187/376/2 190/377/2
-f 87/329/6 81/328/6 187/378/6
-f 185/379/1 188/380/1 183/381/1
-f 88/281/1 82/280/1 186/382/1
-f 191/383/1 192/384/1 188/380/1
-f 193/385/2 190/377/2 194/386/2
-f 188/374/3 192/387/3 190/388/3
-f 189/389/3 193/390/3 169/340/3
-f 174/368/3 195/391/3 191/392/3
-f 179/393/2 194/386/2 83/292/2
-f 196/394/1 186/382/1 192/384/1
-f 192/387/3 186/370/3 194/395/3
-f 193/390/3 179/396/3 172/348/3
-f 195/391/3 176/354/3 196/397/3
-f 91/182/2 105/398/2 89/180/2
-f 89/180/2 95/399/2 117/400/2
+f 99/192/6 100/193/6 74/194/6
+f 98/195/3 99/196/3 75/197/3
+f 101/198/6 102/199/6 100/193/6
+f 97/200/3 101/201/3 99/196/3
+f 103/202/3 91/203/3 101/201/3
+f 91/203/3 90/204/3 104/205/3
+f 105/206/3 78/207/3 77/208/3
+f 100/209/3 106/210/3 73/211/3
+f 100/209/3 102/212/3 107/213/3
+f 108/214/1 106/215/1 109/216/1
+f 85/217/5 73/218/5 106/219/5
+f 104/220/2 107/221/2 102/222/2
+f 86/223/2 78/224/2 105/225/2
+f 110/226/2 111/227/2 107/221/2
+f 112/228/1 109/216/1 113/229/1
+f 107/213/3 111/230/3 109/231/3
+f 108/232/3 112/233/3 114/234/3
+f 90/204/3 115/235/3 110/236/3
+f 116/237/1 113/229/1 77/238/1
+f 110/226/2 117/239/2 105/225/2
+f 111/230/7 105/206/7 113/240/7
+f 112/233/3 116/241/3 118/242/3
+f 115/235/3 95/186/3 117/243/3
+f 119/244/1 120/245/1 121/246/1
+f 120/247/4 93/184/4 92/183/4
+f 88/248/3 122/249/3 119/250/3
+f 123/251/6 121/252/6 92/253/6
+f 74/194/6 124/254/6 125/255/6
+f 75/197/3 125/256/3 123/257/3
+f 124/254/6 126/258/6 127/259/6
+f 125/256/3 127/260/3 128/261/3
+f 127/260/3 129/262/3 130/263/3
+f 131/264/3 132/265/3 129/262/3
+f 83/266/3 82/267/3 133/268/3
+f 73/211/3 134/269/3 124/270/3
+f 124/270/3 134/269/3 135/271/3
+f 136/272/2 134/273/2 137/274/2
+f 134/275/5 73/218/5 85/217/5
+f 126/276/1 135/277/1 131/278/1
+f 133/279/1 82/280/1 88/281/1
+f 135/277/1 138/282/1 139/283/1
+f 140/284/2 136/272/2 141/285/2
+f 136/286/3 138/287/3 135/271/3
+f 114/234/3 141/288/3 137/289/3
+f 139/290/3 142/291/3 132/265/3
+f 83/292/2 140/284/2 143/293/2
+f 139/283/1 138/282/1 133/279/1
+f 140/294/7 133/268/7 138/287/7
+f 118/242/3 143/295/3 141/288/3
+f 144/296/3 119/250/3 142/291/3
+f 145/297/2 94/298/2 146/299/2
+f 94/185/4 93/184/4 147/300/4
+f 86/188/3 96/187/3 145/301/3
+f 148/302/5 146/303/5 147/304/5
+f 80/305/5 149/306/5 150/307/5
+f 79/308/3 150/309/3 148/310/3
+f 149/306/5 151/311/5 152/312/5
+f 150/309/3 152/313/3 153/314/3
+f 152/313/3 154/315/3 155/316/3
+f 156/317/3 157/318/3 154/315/3
+f 77/208/3 78/207/3 158/319/3
+f 81/320/3 159/321/3 149/322/3
+f 149/322/3 159/321/3 160/323/3
+f 161/324/1 159/325/1 162/326/1
+f 159/327/6 81/328/6 87/329/6
+f 151/330/2 160/331/2 156/332/2
+f 158/333/2 78/224/2 86/223/2
+f 160/331/2 163/334/2 164/335/2
+f 165/336/1 161/324/1 166/337/1
+f 161/338/3 163/339/3 160/323/3
+f 167/340/3 166/341/3 162/342/3
+f 164/343/3 168/344/3 157/318/3
+f 77/238/1 165/336/1 169/345/1
+f 163/334/2 158/333/2 170/346/2
+f 165/347/3 158/319/3 163/339/3
+f 171/348/3 169/349/3 166/341/3
+f 170/350/3 145/301/3 168/344/3
+f 172/351/1 173/352/1 174/353/1
+f 147/300/4 93/184/4 120/247/4
+f 175/354/3 122/249/3 88/248/3
+f 172/355/5 176/356/5 177/357/5
+f 178/358/5 179/359/5 80/305/5
+f 177/360/3 178/361/3 79/308/3
+f 180/362/5 181/363/5 179/359/5
+f 176/364/3 180/365/3 178/361/3
+f 182/366/3 174/367/3 180/365/3
+f 174/367/3 173/368/3 183/369/3
+f 184/370/3 82/267/3 83/266/3
+f 179/371/3 185/372/3 81/320/3
+f 179/371/3 181/373/3 186/374/3
+f 187/375/2 185/376/2 188/377/2
+f 87/329/6 81/328/6 185/378/6
+f 183/379/1 186/380/1 181/381/1
+f 88/281/1 82/280/1 184/382/1
+f 189/383/1 190/384/1 186/380/1
+f 191/385/2 188/377/2 192/386/2
+f 186/374/3 190/387/3 188/388/3
+f 187/389/3 191/390/3 167/340/3
+f 173/368/3 193/391/3 189/392/3
+f 194/393/2 192/386/2 83/292/2
+f 195/394/1 184/382/1 190/384/1
+f 190/387/3 184/370/3 192/395/3
+f 191/390/3 194/396/3 171/348/3
+f 193/391/3 175/354/3 195/397/3
+f 91/182/2 103/398/2 89/180/2
+f 89/180/2 95/399/2 115/400/2
f 96/401/2 95/399/2 94/298/2
-f 117/400/2 90/181/2 89/180/2
+f 115/400/2 90/181/2 89/180/2
f 94/298/2 95/399/2 89/180/2
f 89/402/4 92/183/4 94/185/4
-f 118/243/3 95/186/3 86/188/3
-f 98/191/6 197/403/6 92/253/6
+f 117/243/3 95/186/3 86/188/3
+f 98/191/6 196/403/6 92/253/6
f 92/253/6 89/189/6 98/191/6
-f 105/404/6 97/190/6 89/189/6
-f 75/405/6 101/192/6 74/194/6
-f 197/406/3 98/195/3 75/197/3
-f 101/192/6 103/198/6 102/193/6
-f 98/195/3 97/200/3 101/196/3
-f 97/200/3 105/202/3 103/201/3
-f 103/201/3 91/203/3 106/205/3
-f 115/240/3 107/206/3 77/208/3
-f 74/407/3 102/209/3 73/211/3
-f 108/210/3 102/209/3 109/213/3
-f 114/228/1 110/214/1 111/216/1
-f 110/408/5 85/217/5 108/219/5
-f 103/409/2 106/220/2 104/222/2
-f 118/239/2 86/223/2 107/225/2
-f 106/220/2 112/226/2 109/221/2
-f 99/237/1 114/228/1 115/229/1
-f 108/210/3 109/213/3 111/231/3
-f 85/410/3 110/232/3 116/234/3
-f 106/205/3 90/204/3 112/236/3
-f 76/411/1 99/237/1 77/238/1
-f 113/227/2 112/226/2 107/225/2
-f 111/231/7 113/230/7 115/240/7
-f 116/234/3 114/233/3 119/242/3
-f 112/236/3 117/235/3 118/243/3
-f 122/246/1 132/412/1 131/413/1
-f 131/413/1 134/414/1 122/246/1
-f 144/415/1 120/244/1 122/246/1
-f 123/416/1 121/245/1 120/244/1
-f 122/246/1 134/414/1 144/415/1
-f 122/417/4 121/247/4 92/183/4
-f 145/296/3 88/248/3 120/250/3
-f 92/253/6 197/403/6 124/251/6
-f 124/251/6 130/418/6 122/252/6
-f 132/419/6 122/252/6 130/418/6
-f 75/405/6 74/194/6 127/255/6
-f 197/406/3 75/197/3 124/257/3
-f 127/255/6 126/254/6 129/259/6
-f 124/257/3 127/256/3 130/261/3
-f 130/261/3 129/260/3 132/263/3
-f 129/260/3 133/264/3 131/262/3
-f 142/294/3 83/266/3 135/268/3
-f 74/407/3 73/211/3 126/270/3
-f 128/420/3 126/270/3 137/271/3
-f 143/285/2 138/272/2 139/274/2
-f 139/421/5 136/275/5 85/217/5
-f 129/422/1 128/276/1 133/278/1
-f 145/423/1 135/279/1 88/281/1
-f 133/278/1 137/277/1 141/283/1
-f 125/293/2 142/284/2 143/285/2
-f 136/269/3 138/286/3 137/271/3
-f 85/410/3 116/234/3 139/289/3
-f 133/264/3 141/290/3 134/265/3
-f 84/424/2 83/292/2 125/293/2
-f 145/423/1 141/283/1 135/279/1
-f 138/286/7 142/294/7 140/287/7
-f 116/234/3 119/242/3 143/288/3
-f 141/290/3 145/296/3 144/291/3
-f 147/299/2 157/425/2 156/426/2
-f 156/426/2 159/427/2 147/299/2
-f 170/428/2 146/297/2 147/299/2
-f 96/401/2 94/298/2 146/297/2
-f 147/299/2 159/427/2 170/428/2
-f 147/429/4 94/185/4 148/300/4
-f 171/350/3 86/188/3 146/301/3
-f 148/304/5 198/430/5 149/302/5
-f 149/302/5 155/431/5 147/303/5
-f 157/432/5 147/303/5 155/431/5
-f 79/433/5 80/305/5 152/307/5
-f 198/434/3 79/308/3 149/310/3
-f 152/307/5 151/306/5 154/312/5
-f 149/310/3 152/309/3 155/314/3
-f 155/314/3 154/313/3 157/316/3
-f 154/313/3 158/317/3 156/315/3
-f 167/347/3 77/208/3 160/319/3
-f 80/435/3 81/320/3 151/322/3
-f 153/436/3 151/322/3 162/323/3
-f 168/337/1 163/324/1 164/326/1
-f 164/437/6 161/327/6 87/329/6
-f 154/438/2 153/330/2 158/332/2
-f 171/346/2 160/333/2 86/223/2
-f 158/332/2 162/331/2 166/335/2
-f 150/345/1 167/336/1 168/337/1
-f 161/321/3 163/338/3 162/323/3
-f 87/439/3 169/340/3 164/342/3
-f 158/317/3 166/343/3 159/318/3
-f 76/411/1 77/238/1 150/345/1
-f 166/335/2 165/334/2 171/346/2
-f 163/338/3 167/347/3 165/339/3
-f 169/340/3 172/348/3 168/341/3
-f 166/343/3 171/350/3 170/344/3
-f 175/353/1 184/440/1 173/351/1
-f 173/351/1 176/441/1 195/442/1
-f 123/416/1 176/441/1 121/245/1
-f 195/442/1 174/352/1 173/351/1
-f 121/245/1 176/441/1 173/351/1
-f 173/443/4 148/300/4 121/247/4
-f 196/397/3 176/354/3 88/248/3
-f 178/357/5 198/430/5 148/304/5
-f 148/304/5 173/355/5 178/357/5
-f 184/444/5 177/356/5 173/355/5
-f 79/433/5 180/358/5 80/305/5
-f 198/434/3 178/360/3 79/308/3
-f 180/358/5 182/362/5 181/359/5
-f 178/360/3 177/364/3 180/361/3
-f 177/364/3 184/366/3 182/365/3
-f 182/365/3 175/367/3 185/369/3
-f 194/395/3 186/370/3 83/266/3
-f 80/435/3 181/371/3 81/320/3
-f 187/372/3 181/371/3 188/374/3
-f 193/385/2 189/375/2 190/377/2
-f 189/445/6 87/329/6 187/378/6
-f 182/446/1 185/379/1 183/381/1
-f 196/394/1 88/281/1 186/382/1
-f 185/379/1 191/383/1 188/380/1
-f 179/393/2 193/385/2 194/386/2
-f 187/372/3 188/374/3 190/388/3
-f 87/439/3 189/389/3 169/340/3
-f 185/369/3 174/368/3 191/392/3
-f 84/424/2 179/393/2 83/292/2
-f 191/383/1 196/394/1 192/384/1
-f 190/388/3 192/387/3 194/395/3
-f 169/340/3 193/390/3 172/348/3
-f 191/392/3 195/391/3 196/397/3
-g HsVsAnzUnten_Cube.009_HsVsAnzUnten_Cube.009_Anzeige
-usemtl Anzeige
-f 99/447/3 76/448/3 100/449/3
-f 100/449/3 84/450/3 125/451/3
-f 100/449/3 76/448/3 150/452/3
-f 179/453/3 84/450/3 100/449/3
-f 119/454/3 99/447/3 100/449/3
-f 119/454/3 100/449/3 125/451/3
-f 172/455/3 100/449/3 150/452/3
-f 172/455/3 179/453/3 100/449/3
+f 103/404/6 97/190/6 89/189/6
+f 75/405/6 99/192/6 74/194/6
+f 196/406/3 98/195/3 75/197/3
+f 99/192/6 101/198/6 100/193/6
+f 98/195/3 97/200/3 99/196/3
+f 97/200/3 103/202/3 101/201/3
+f 101/201/3 91/203/3 104/205/3
+f 113/240/3 105/206/3 77/208/3
+f 74/407/3 100/209/3 73/211/3
+f 106/210/3 100/209/3 107/213/3
+f 112/228/1 108/214/1 109/216/1
+f 108/408/5 85/217/5 106/219/5
+f 101/409/2 104/220/2 102/222/2
+f 117/239/2 86/223/2 105/225/2
+f 104/220/2 110/226/2 107/221/2
+f 116/237/1 112/228/1 113/229/1
+f 106/210/3 107/213/3 109/231/3
+f 85/410/3 108/232/3 114/234/3
+f 104/205/3 90/204/3 110/236/3
+f 76/411/1 116/237/1 77/238/1
+f 111/227/2 110/226/2 105/225/2
+f 109/231/7 111/230/7 113/240/7
+f 114/234/3 112/233/3 118/242/3
+f 110/236/3 115/235/3 117/243/3
+f 121/246/1 130/412/1 129/413/1
+f 129/413/1 132/414/1 121/246/1
+f 142/415/1 119/244/1 121/246/1
+f 122/416/1 120/245/1 119/244/1
+f 121/246/1 132/414/1 142/415/1
+f 121/417/4 120/247/4 92/183/4
+f 144/296/3 88/248/3 119/250/3
+f 92/253/6 196/403/6 123/251/6
+f 123/251/6 128/418/6 121/252/6
+f 130/419/6 121/252/6 128/418/6
+f 75/405/6 74/194/6 125/255/6
+f 196/406/3 75/197/3 123/257/3
+f 125/255/6 124/254/6 127/259/6
+f 123/257/3 125/256/3 128/261/3
+f 128/261/3 127/260/3 130/263/3
+f 127/260/3 131/264/3 129/262/3
+f 140/294/3 83/266/3 133/268/3
+f 74/407/3 73/211/3 124/270/3
+f 126/420/3 124/270/3 135/271/3
+f 141/285/2 136/272/2 137/274/2
+f 137/421/5 134/275/5 85/217/5
+f 127/422/1 126/276/1 131/278/1
+f 144/423/1 133/279/1 88/281/1
+f 131/278/1 135/277/1 139/283/1
+f 143/293/2 140/284/2 141/285/2
+f 134/269/3 136/286/3 135/271/3
+f 85/410/3 114/234/3 137/289/3
+f 131/264/3 139/290/3 132/265/3
+f 84/424/2 83/292/2 143/293/2
+f 144/423/1 139/283/1 133/279/1
+f 136/286/7 140/294/7 138/287/7
+f 114/234/3 118/242/3 141/288/3
+f 139/290/3 144/296/3 142/291/3
+f 146/299/2 155/425/2 154/426/2
+f 154/426/2 157/427/2 146/299/2
+f 168/428/2 145/297/2 146/299/2
+f 96/401/2 94/298/2 145/297/2
+f 146/299/2 157/427/2 168/428/2
+f 146/429/4 94/185/4 147/300/4
+f 170/350/3 86/188/3 145/301/3
+f 147/304/5 197/430/5 148/302/5
+f 148/302/5 153/431/5 146/303/5
+f 155/432/5 146/303/5 153/431/5
+f 79/433/5 80/305/5 150/307/5
+f 197/434/3 79/308/3 148/310/3
+f 150/307/5 149/306/5 152/312/5
+f 148/310/3 150/309/3 153/314/3
+f 153/314/3 152/313/3 155/316/3
+f 152/313/3 156/317/3 154/315/3
+f 165/347/3 77/208/3 158/319/3
+f 80/435/3 81/320/3 149/322/3
+f 151/436/3 149/322/3 160/323/3
+f 166/337/1 161/324/1 162/326/1
+f 162/437/6 159/327/6 87/329/6
+f 152/438/2 151/330/2 156/332/2
+f 170/346/2 158/333/2 86/223/2
+f 156/332/2 160/331/2 164/335/2
+f 169/345/1 165/336/1 166/337/1
+f 159/321/3 161/338/3 160/323/3
+f 87/439/3 167/340/3 162/342/3
+f 156/317/3 164/343/3 157/318/3
+f 76/411/1 77/238/1 169/345/1
+f 164/335/2 163/334/2 170/346/2
+f 161/338/3 165/347/3 163/339/3
+f 167/340/3 171/348/3 166/341/3
+f 164/343/3 170/350/3 168/344/3
+f 174/353/1 182/440/1 172/351/1
+f 172/351/1 175/441/1 193/442/1
+f 122/416/1 175/441/1 120/245/1
+f 193/442/1 173/352/1 172/351/1
+f 120/245/1 175/441/1 172/351/1
+f 172/443/4 147/300/4 120/247/4
+f 195/397/3 175/354/3 88/248/3
+f 177/357/5 197/430/5 147/304/5
+f 147/304/5 172/355/5 177/357/5
+f 182/444/5 176/356/5 172/355/5
+f 79/433/5 178/358/5 80/305/5
+f 197/434/3 177/360/3 79/308/3
+f 178/358/5 180/362/5 179/359/5
+f 177/360/3 176/364/3 178/361/3
+f 176/364/3 182/366/3 180/365/3
+f 180/365/3 174/367/3 183/369/3
+f 192/395/3 184/370/3 83/266/3
+f 80/435/3 179/371/3 81/320/3
+f 185/372/3 179/371/3 186/374/3
+f 191/385/2 187/375/2 188/377/2
+f 187/445/6 87/329/6 185/378/6
+f 180/446/1 183/379/1 181/381/1
+f 195/394/1 88/281/1 184/382/1
+f 183/379/1 189/383/1 186/380/1
+f 194/393/2 191/385/2 192/386/2
+f 185/372/3 186/374/3 188/388/3
+f 87/439/3 187/389/3 167/340/3
+f 183/369/3 173/368/3 189/392/3
+f 84/424/2 194/393/2 83/292/2
+f 189/383/1 195/394/1 190/384/1
+f 188/388/3 190/387/3 192/395/3
+f 167/340/3 191/390/3 171/348/3
+f 189/392/3 193/391/3 195/397/3
+g HsVsAnzUnten_Cube.008_HsVsAnzUnten_Cube.008_Anzeige.009
+usemtl Anzeige.009
+f 116/447/3 76/448/3 198/449/3
+f 198/449/3 84/450/3 143/451/3
+f 198/449/3 76/448/3 169/452/3
+f 194/453/3 84/450/3 198/449/3
+f 118/454/3 116/447/3 198/449/3
+f 118/454/3 198/449/3 143/451/3
+f 171/455/3 198/449/3 169/452/3
+f 171/455/3 194/453/3 198/449/3
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr0.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr0.obj
index 972e0ad..ad7ec3e 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr0.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr0.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_top_smr0.mtl
-o HsVsAnzOben_Cube.006
+o HsVsAnzOben_Cube.001
v 0.028581 -0.505448 -0.325575
v 0.028581 -0.505448 -0.439611
v -0.028581 -0.505448 -0.439611
@@ -33,8 +33,8 @@ v -0.028581 -0.505448 -0.325575
v 0.138251 -0.045773 -0.444371
v 0.138251 -0.070195 -0.541156
v 0.138251 -0.064457 -0.541156
-v -0.000000 -0.045773 -0.444371
-v -0.000000 -0.210259 -0.444371
+v 0.000000 -0.045773 -0.444371
+v 0.000000 -0.210259 -0.444371
v 0.138251 -0.210259 -0.444371
v 0.138251 -0.098130 -0.541156
v 0.138251 -0.210259 -0.541156
@@ -43,8 +43,8 @@ v 0.114848 -0.045773 -0.541156
v 0.107395 -0.045773 -0.541156
v 0.107395 -0.064457 -0.541156
v 0.107395 -0.064457 -0.597615
-v -0.000000 -0.064457 -0.597615
-v -0.000000 -0.064457 -0.541156
+v 0.000000 -0.064457 -0.597615
+v 0.000000 -0.064457 -0.541156
v 0.114848 -0.064457 -0.541156
v 0.114848 -0.064457 -0.597615
v 0.138251 -0.045773 -0.541156
@@ -52,21 +52,21 @@ v 0.114848 -0.098130 -0.566450
v 0.114848 -0.210259 -0.566450
v 0.107395 -0.210259 -0.566450
v 0.107395 -0.070195 -0.597615
-v -0.000000 -0.070195 -0.597615
+v 0.000000 -0.070195 -0.597615
v 0.114848 -0.070195 -0.597615
v 0.107395 -0.070195 -0.541156
v 0.107395 -0.080599 -0.597615
-v -0.000000 -0.070195 -0.541156
+v 0.000000 -0.070195 -0.541156
v 0.114848 -0.070195 -0.541156
v 0.114848 -0.080599 -0.541156
v 0.114848 -0.080599 -0.597615
v 0.107395 -0.080599 -0.541156
v 0.107395 -0.098130 -0.566450
-v -0.000000 -0.080599 -0.541156
+v 0.000000 -0.080599 -0.541156
v 0.138251 -0.080599 -0.541156
v 0.107395 -0.098130 -0.541156
v 0.114848 -0.098130 -0.541156
-v -0.000000 -0.098130 -0.541156
+v 0.000000 -0.098130 -0.541156
v -0.138251 -0.098130 -0.541156
v -0.138251 -0.210259 -0.444371
v -0.138251 -0.045773 -0.444371
@@ -98,12 +98,12 @@ v -0.107395 -0.098130 -0.541156
v -0.114848 -0.098130 -0.541156
v 0.138251 -0.322387 -0.541156
v 0.138251 -0.374745 -0.444371
-v -0.000000 -0.374745 -0.444371
+v 0.000000 -0.374745 -0.444371
v 0.107395 -0.374745 -0.541156
-v -0.000000 -0.356061 -0.566450
+v 0.000000 -0.356061 -0.566450
v 0.107395 -0.356061 -0.566450
v 0.107395 -0.356061 -0.541156
-v -0.000000 -0.356061 -0.541156
+v 0.000000 -0.356061 -0.541156
v 0.114848 -0.356061 -0.566450
v 0.114848 -0.356061 -0.541156
v 0.114848 -0.374745 -0.541156
@@ -112,21 +112,21 @@ v 0.138251 -0.374745 -0.541156
v 0.114848 -0.350322 -0.541156
v 0.138251 -0.350322 -0.541156
v 0.114848 -0.322387 -0.566450
-v -0.000000 -0.350322 -0.566450
+v 0.000000 -0.350322 -0.566450
v 0.107395 -0.350322 -0.566450
v 0.114848 -0.350322 -0.566450
v 0.107395 -0.339919 -0.566450
v 0.107395 -0.350322 -0.541156
-v -0.000000 -0.350322 -0.541156
+v 0.000000 -0.350322 -0.541156
v 0.114848 -0.339919 -0.566450
v 0.114848 -0.339919 -0.541156
v 0.107395 -0.322387 -0.566450
v 0.107395 -0.339919 -0.541156
-v -0.000000 -0.339919 -0.541156
+v 0.000000 -0.339919 -0.541156
v 0.138251 -0.339919 -0.541156
v 0.107395 -0.322387 -0.541156
v 0.114848 -0.322387 -0.541156
-v -0.000000 -0.322387 -0.541156
+v 0.000000 -0.322387 -0.541156
v 0.107395 -0.210259 -0.541156
v -0.138251 -0.374745 -0.444371
v -0.138251 -0.350322 -0.541156
@@ -153,9 +153,9 @@ v -0.138251 -0.339919 -0.541156
v -0.107395 -0.322387 -0.541156
v -0.114848 -0.322387 -0.541156
v -0.107395 -0.210259 -0.541156
-v -0.000000 -0.045773 -0.541156
-v -0.000000 -0.374745 -0.541156
-v -0.000000 -0.210259 -0.541156
+v 0.000000 -0.045773 -0.541156
+v 0.000000 -0.374745 -0.541156
+v 0.000000 -0.210259 -0.541156
v 0.028581 -0.505448 -0.268412
v 0.028581 -0.505448 -0.496774
v -0.028581 -0.505448 -0.496774
@@ -528,24 +528,24 @@ vt 0.979997 0.896154
vt 0.913317 0.407128
vt 0.773970 0.379437
vt 0.488140 0.842607
-vt -0.000000 1.000000
-vt -0.000000 0.875212
-vt 0.119520 0.875212
-vt 0.239040 0.875212
-vt 0.239040 1.000000
-vt -0.000000 0.750424
-vt 0.239040 0.750424
-vt 0.119520 1.000000
-vt 0.119520 0.750424
+vt 0.003906 1.011719
+vt 0.003906 0.500000
+vt 0.500000 0.500000
+vt 0.996094 0.500000
+vt 0.996094 1.011719
+vt 0.003906 -0.011719
+vt 0.996094 -0.011719
+vt 0.500000 1.011719
+vt 0.500000 -0.011719
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
-vn 1.0000 0.0000 -0.0000
+vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
-vn 0.0000 0.0000 1.0000
-vn 0.0000 -1.0000 0.0000
+vn 0.0000 -0.0000 1.0000
+vn 0.0000 -1.0000 -0.0000
vn 0.0000 -0.8716 -0.4903
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Mast
-usemtl Mast
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Mast.011
+usemtl Mast.011
s 1
f 1/1/1 2/2/1 3/3/1
f 4/4/2 5/5/2 6/6/2
@@ -591,8 +591,8 @@ f 27/40/3 23/38/3 13/13/3
f 25/47/1 27/44/1 7/46/1
f 19/61/1 27/44/1 20/48/1
f 7/46/1 13/45/1 8/50/1
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Schirm
-usemtl Schirm
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Schirm.011
+usemtl Schirm.011
f 29/62/3 30/63/3 31/64/3
f 32/65/5 33/66/5 34/67/5
f 35/68/4 36/69/4 37/70/4
@@ -841,8 +841,8 @@ f 143/295/4 145/294/4 147/303/4
f 121/232/4 146/297/4 125/241/4
f 144/299/4 148/298/4 150/305/4
f 69/368/6 82/306/6 151/308/6
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Anzeige
-usemtl Anzeige
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Anzeige.011
+usemtl Anzeige.011
f 63/369/4 126/370/4 154/371/4
f 154/371/4 151/372/4 93/373/4
f 154/371/4 126/370/4 123/374/4
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr30.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr30.obj
index e6d0918..037f0d4 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr30.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr30.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_top_smr30.mtl
-o HsVsAnzOben_Cube.006
+o HsVsAnzOben_Cube.001
v 0.170849 -0.505448 -0.278615
v 0.221732 -0.505448 -0.380670
v 0.170575 -0.505448 -0.406176
@@ -528,15 +528,15 @@ vt 0.979997 0.896154
vt 0.913317 0.407128
vt 0.773970 0.379437
vt 0.488140 0.842607
-vt -0.000000 1.000000
-vt -0.000000 0.875212
-vt 0.119520 0.875212
-vt 0.239040 0.875212
-vt 0.239040 1.000000
-vt -0.000000 0.750424
-vt 0.239040 0.750424
-vt 0.119520 1.000000
-vt 0.119520 0.750424
+vt 0.003906 1.011719
+vt 0.003906 0.500000
+vt 0.500000 0.500000
+vt 0.996094 0.500000
+vt 0.996094 1.011719
+vt 0.003906 -0.011719
+vt 0.996094 -0.011719
+vt 0.500000 1.011719
+vt 0.500000 -0.011719
vn 0.0000 1.0000 -0.0000
vn -0.8949 0.0000 -0.4462
vn 0.8949 0.0000 0.4462
@@ -544,8 +544,8 @@ vn 0.4462 0.0000 -0.8949
vn -0.4462 0.0000 0.8949
vn 0.0000 -1.0000 -0.0000
vn 0.2188 -0.8716 -0.4388
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Mast
-usemtl Mast
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Mast.011
+usemtl Mast.011
s 1
f 1/1/1 2/2/1 3/3/1
f 4/4/2 5/5/2 6/6/2
@@ -591,8 +591,8 @@ f 27/40/3 23/38/3 13/13/3
f 25/47/1 27/44/1 7/46/1
f 19/61/1 27/44/1 20/48/1
f 7/46/1 13/45/1 8/50/1
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Schirm
-usemtl Schirm
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Schirm.011
+usemtl Schirm.011
f 29/62/3 30/63/3 31/64/3
f 32/65/5 33/66/5 34/67/5
f 35/68/4 36/69/4 37/70/4
@@ -841,8 +841,8 @@ f 143/295/4 145/294/4 147/303/4
f 121/232/4 146/297/4 125/241/4
f 144/299/4 148/298/4 150/305/4
f 69/368/6 82/306/6 151/308/6
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Anzeige
-usemtl Anzeige
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Anzeige.011
+usemtl Anzeige.011
f 63/369/4 126/370/4 154/371/4
f 154/371/4 151/372/4 93/373/4
f 154/371/4 126/370/4 123/374/4
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr45.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr45.obj
index 96e19ff..2ba17df 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr45.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr45.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_top_smr45.mtl
-o HsVsAnzOben_Cube.006
+o HsVsAnzOben_Cube.001
v 0.250426 -0.505448 -0.210006
v 0.331062 -0.505448 -0.290642
v 0.290642 -0.505448 -0.331062
@@ -97,7 +97,7 @@ v 0.284897 -0.080599 -0.480413
v 0.306715 -0.098130 -0.458595
v 0.301445 -0.098130 -0.463865
v 0.480413 -0.322387 -0.284897
-v 0.411976 -0.374745 -0.216459
+v 0.411976 -0.374745 -0.216460
v 0.314218 -0.374745 -0.314218
v 0.458595 -0.374745 -0.306715
v 0.400541 -0.356061 -0.400541
@@ -128,7 +128,7 @@ v 0.458595 -0.322387 -0.306715
v 0.463865 -0.322387 -0.301445
v 0.382655 -0.322387 -0.382655
v 0.458595 -0.210259 -0.306715
-v 0.216459 -0.374745 -0.411976
+v 0.216460 -0.374745 -0.411976
v 0.284897 -0.350322 -0.480413
v 0.284897 -0.356061 -0.480413
v 0.284897 -0.322387 -0.480413
@@ -528,24 +528,24 @@ vt 0.979997 0.896154
vt 0.913317 0.407128
vt 0.773970 0.379437
vt 0.488140 0.842607
-vt -0.000000 1.000000
-vt -0.000000 0.875212
-vt 0.119520 0.875212
-vt 0.239040 0.875212
-vt 0.239040 1.000000
-vt -0.000000 0.750424
-vt 0.239040 0.750424
-vt 0.119520 1.000000
-vt 0.119520 0.750424
+vt 0.003906 1.011719
+vt 0.003906 0.500000
+vt 0.500000 0.500000
+vt 0.996094 0.500000
+vt 0.996094 1.011719
+vt 0.003906 -0.011719
+vt 0.996094 -0.011719
+vt 0.500000 1.011719
+vt 0.500000 -0.011719
vn 0.0000 1.0000 0.0000
vn -0.7071 0.0000 -0.7071
vn 0.7071 0.0000 0.7071
vn 0.7071 0.0000 -0.7071
vn -0.7071 0.0000 0.7071
-vn 0.0000 -1.0000 0.0000
+vn 0.0000 -1.0000 -0.0000
vn 0.3467 -0.8716 -0.3467
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Mast
-usemtl Mast
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Mast.011
+usemtl Mast.011
s 1
f 1/1/1 2/2/1 3/3/1
f 4/4/2 5/5/2 6/6/2
@@ -591,8 +591,8 @@ f 27/40/3 23/38/3 13/13/3
f 25/47/1 27/44/1 7/46/1
f 19/61/1 27/44/1 20/48/1
f 7/46/1 13/45/1 8/50/1
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Schirm
-usemtl Schirm
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Schirm.011
+usemtl Schirm.011
f 29/62/3 30/63/3 31/64/3
f 32/65/5 33/66/5 34/67/5
f 35/68/4 36/69/4 37/70/4
@@ -841,8 +841,8 @@ f 143/295/4 145/294/4 147/303/4
f 121/232/4 146/297/4 125/241/4
f 144/299/4 148/298/4 150/305/4
f 69/368/6 82/306/6 151/308/6
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Anzeige
-usemtl Anzeige
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Anzeige.011
+usemtl Anzeige.011
f 63/369/4 126/370/4 154/371/4
f 154/371/4 151/372/4 93/373/4
f 154/371/4 126/370/4 123/374/4
diff --git a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr60.obj b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr60.obj
index 5af870a..c99c697 100644
--- a/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr60.obj
+++ b/advtrains_signals_ks/models/advtrains_signals_ks_zs_top_smr60.obj
@@ -1,7 +1,7 @@
-# Blender v2.92.0 OBJ File: ''
+# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib advtrains_signals_ks_zs_top_smr60.mtl
-o HsVsAnzOben_Cube.006
+o HsVsAnzOben_Cube.001
v 0.304121 -0.505448 -0.119693
v 0.406176 -0.505448 -0.170575
v 0.380670 -0.505448 -0.221732
@@ -528,15 +528,15 @@ vt 0.979997 0.896154
vt 0.913317 0.407128
vt 0.773970 0.379437
vt 0.488140 0.842607
-vt -0.000000 1.000000
-vt -0.000000 0.875212
-vt 0.119520 0.875212
-vt 0.239040 0.875212
-vt 0.239040 1.000000
-vt -0.000000 0.750424
-vt 0.239040 0.750424
-vt 0.119520 1.000000
-vt 0.119520 0.750424
+vt 0.003906 1.011719
+vt 0.003906 0.500000
+vt 0.500000 0.500000
+vt 0.996094 0.500000
+vt 0.996094 1.011719
+vt 0.003906 -0.011719
+vt 0.996094 -0.011719
+vt 0.500000 1.011719
+vt 0.500000 -0.011719
vn 0.0000 1.0000 -0.0000
vn -0.4462 0.0000 -0.8949
vn 0.4462 0.0000 0.8949
@@ -544,8 +544,8 @@ vn 0.8949 0.0000 -0.4462
vn -0.8949 0.0000 0.4462
vn 0.0000 -1.0000 0.0000
vn 0.4388 -0.8716 -0.2188
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Mast
-usemtl Mast
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Mast.011
+usemtl Mast.011
s 1
f 1/1/1 2/2/1 3/3/1
f 4/4/2 5/5/2 6/6/2
@@ -591,8 +591,8 @@ f 27/40/3 23/38/3 13/13/3
f 25/47/1 27/44/1 7/46/1
f 19/61/1 27/44/1 20/48/1
f 7/46/1 13/45/1 8/50/1
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Schirm
-usemtl Schirm
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Schirm.011
+usemtl Schirm.011
f 29/62/3 30/63/3 31/64/3
f 32/65/5 33/66/5 34/67/5
f 35/68/4 36/69/4 37/70/4
@@ -841,8 +841,8 @@ f 143/295/4 145/294/4 147/303/4
f 121/232/4 146/297/4 125/241/4
f 144/299/4 148/298/4 150/305/4
f 69/368/6 82/306/6 151/308/6
-g HsVsAnzOben_Cube.006_HsVsAnzOben_Cube.006_Anzeige
-usemtl Anzeige
+g HsVsAnzOben_Cube.001_HsVsAnzOben_Cube.001_Anzeige.011
+usemtl Anzeige.011
f 63/369/4 126/370/4 154/371/4
f 154/371/4 151/372/4 93/373/4
f 154/371/4 126/370/4 123/374/4
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png b/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png
index dbbee5d..81b1128 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_12.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_12.png
index cba5222..bc5f758 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_12.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_12.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_16.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_16.png
index a35fa93..ebbdd3d 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_16.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_16.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_20.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_20.png
new file mode 100644
index 0000000..71b540d
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_20.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_4.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_4.png
new file mode 100644
index 0000000..21318b3
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_4.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_6.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_6.png
new file mode 100644
index 0000000..b7c5a51
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_6.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_8.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_8.png
index abfa10c..f9ff54f 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_8.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_8.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_e.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_e.png
index 3d55af0..4ff8ce5 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_e.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_e.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_hfs.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_hfs.png
index 31dffe2..e5d8a24 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_hfs.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_hfs.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_lf7.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_lf7.png
new file mode 100644
index 0000000..8ce24dc
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_lf7.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x1.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x1.png
new file mode 100644
index 0000000..19f860a
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x1.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x2.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x2.png
new file mode 100644
index 0000000..dd86d09
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x2.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x3.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x3.png
new file mode 100644
index 0000000..f343fc4
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x3.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x4.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x4.png
new file mode 100644
index 0000000..98c0248
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x4.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x5.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x5.png
new file mode 100644
index 0000000..d9d21bd
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne3x5.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne4.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne4.png
new file mode 100644
index 0000000..4efbe57
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_ne4.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_off.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_off.png
new file mode 100644
index 0000000..6b077ec
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_off.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png
index c4229fd..c60d900 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_pam.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_sign_zs10.png b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_zs10.png
new file mode 100644
index 0000000..e14c64f
--- /dev/null
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_sign_zs10.png
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_12.png b/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_12.png
deleted file mode 100644
index ff8670b..0000000
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_12.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_16.png b/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_16.png
deleted file mode 100644
index ea871e4..0000000
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_16.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_4.png b/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_4.png
deleted file mode 100644
index b3365ec..0000000
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_4.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_6.png b/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_6.png
deleted file mode 100644
index fb21f65..0000000
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_6.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_8.png b/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_8.png
deleted file mode 100644
index 8730262..0000000
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_8.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_off.png b/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_off.png
deleted file mode 100644
index f66f33b..0000000
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_zs3_off.png
+++ /dev/null
Binary files differ
diff --git a/advtrains_train_track/init.lua b/advtrains_train_track/init.lua
index 6bb8b33..87720e2 100755
--- a/advtrains_train_track/init.lua
+++ b/advtrains_train_track/init.lua
@@ -216,39 +216,95 @@ local function get_far_node(pos)
return node
end
+
+local function show_fc_formspec(pos,player)
+ local pname = player:get_player_name()
+ if minetest.is_protected(pos,pname) then
+ minetest.chat_send_player(pname, "Position is protected!")
+ return
+ end
+
+ local meta = minetest.get_meta(pos)
+ local fc = meta:get_string("fc") or ""
+
+ local form = 'formspec_version[4]'..
+ 'size[10,5]'..
+ 'label[0.5,0.4;Advtrains Loading/Unloading Track]'..
+ 'label[0.5,1.1;Set the code to match against the wagon\'s freight code]'..
+ 'label[0.5,1.6;A blank field matches all wagons (default)]'..
+ 'label[0.5,2.1;Use code # to disable the track section]'..
+ 'field[0.5,3;5.5,1;fc;FC;'..minetest.formspec_escape(fc)..']'..
+ 'button[6.5,3;3,1;save;Submit]'
+ minetest.show_formspec(pname, "at_load_unload_"..advtrains.encode_pos(pos), form)
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ local pname = player:get_player_name()
+ local pe = string.match(formname, "^at_load_unload_(............)$")
+ local pos = advtrains.decode_pos(pe)
+ if pos then
+ if minetest.is_protected(pos, pname) then
+ minetest.chat_send_player(pname, "Position is protected!")
+ return
+ end
+
+ if fields.save then
+ minetest.get_meta(pos):set_string("fc",tostring(fields.fc))
+ minetest.chat_send_player(pname,"Freight code set: "..tostring(fields.fc))
+ show_fc_formspec(pos,player)
+ end
+ end
+end)
+
+
local function train_load(pos, train_id, unload)
- local train=advtrains.trains[train_id]
- local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
- if not string.match(below.name, "chest") then
- atprint("this is not a chest! at "..minetest.pos_to_string(pos))
- return
- end
- local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
- if inv and train.velocity < 2 then
- for k, v in ipairs(train.trainparts) do
-
+ local train=advtrains.trains[train_id]
+ local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
+ if not string.match(below.name, "chest") then
+ atprint("this is not a chest! at "..minetest.pos_to_string(pos))
+ return
+ end
+
+ local node_fc = minetest.get_meta(pos):get_string("fc") or ""
+ if node_fc == "#" then
+ --track section is disabled
+ return
+ end
+
+ local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
+ if inv and train.velocity < 2 then
+ for k, v in ipairs(train.trainparts) do
local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v})
if i and i:get_list("box") then
- if not unload then
- for _, item in ipairs(inv:get_list("main")) do
- if i:get_list("box") and i:room_for_item("box", item) then
- i:add_item("box", item)
- inv:remove_item("main", item)
+
+ local wagon_data = advtrains.wagons[v]
+ local wagon_fc
+ if wagon_data.fc then
+ if not wagon_data.fcind then wagon_data.fcind = 1 end
+ wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or ""
+ end
+
+ if node_fc == "" or wagon_fc == node_fc then
+ if not unload then
+ for _, item in ipairs(inv:get_list("main")) do
+ if i:get_list("box") and i:room_for_item("box", item) then
+ i:add_item("box", item)
+ inv:remove_item("main", item)
+ end
end
- end
- else
- for _, item in ipairs(i:get_list("box")) do
- if inv:get_list("main") and inv:room_for_item("main", item) then
- i:remove_item("box", item)
- inv:add_item("main", item)
+ else
+ for _, item in ipairs(i:get_list("box")) do
+ if inv:get_list("main") and inv:room_for_item("main", item) then
+ i:remove_item("box", item)
+ inv:add_item("main", item)
+ end
end
end
end
end
- end
- end
+ end
+ end
end
-
@@ -262,15 +318,18 @@ advtrains.register_tracks("default", {
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
- after_dig_node=function(pos)
- advtrains.invalidate_all_paths()
- advtrains.ndb.clear(pos)
- end,
- advtrains = {
- on_train_enter = function(pos, train_id)
- train_load(pos, train_id, true)
- end,
- },
+ after_dig_node=function(pos)
+ advtrains.invalidate_all_paths()
+ advtrains.ndb.clear(pos)
+ end,
+ on_rightclick = function(pos, node, player)
+ show_fc_formspec(pos, player)
+ end,
+ advtrains = {
+ on_train_enter = function(pos, train_id)
+ train_load(pos, train_id, true)
+ end,
+ },
}
end
}, advtrains.trackpresets.t_30deg_straightonly)
@@ -284,16 +343,18 @@ advtrains.register_tracks("default", {
formats={},
get_additional_definiton = function(def, preset, suffix, rotation)
return {
- after_dig_node=function(pos)
- advtrains.invalidate_all_paths()
- advtrains.ndb.clear(pos)
- end,
-
- advtrains = {
- on_train_enter = function(pos, train_id)
- train_load(pos, train_id, false)
- end,
- },
+ after_dig_node=function(pos)
+ advtrains.invalidate_all_paths()
+ advtrains.ndb.clear(pos)
+ end,
+ on_rightclick = function(pos, node, player)
+ show_fc_formspec(pos, player)
+ end,
+ advtrains = {
+ on_train_enter = function(pos, train_id)
+ train_load(pos, train_id, false)
+ end,
+ },
}
end
}, advtrains.trackpresets.t_30deg_straightonly)
diff --git a/atc_command.txt b/atc_command.txt
index 9f4eb50..5a1c8ff 100644
--- a/atc_command.txt
+++ b/atc_command.txt
@@ -51,6 +51,10 @@ Kick all passengers out of the trains
This command kicks all passengers (non-driving players) off the train. This command works only
if the train is stopped and its doors are open.
+Cpl
+Temporarily switch the train to "Autocouple" mode and wait for coupling.
+This command makes the train continue at its current speed until it hits another standing wagon or train. Then, it couples to this train and ATC command execution continues.
+
# conditional statements:
I<condition><code>;
diff --git a/modpack.conf b/modpack.conf
index e01f462..5185be4 100644
--- a/modpack.conf
+++ b/modpack.conf
@@ -2,3 +2,4 @@ name=advtrains
title=Advanced Trains
description=Realistic trains and various equipment for railways, with a focus on automated train operation. No trains included, please install those separately.
author=orwell96
+min_minetest_version=5.4 \ No newline at end of file
diff --git a/readme.txt b/readme.txt
deleted file mode 100644
index 05a5d5e..0000000
--- a/readme.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-
-## ADVTRAINS ## realistic trains in Minetest!
-by orwell96 and contributors(see below)
-
-For up-to-date information, visit https://advtrains.de/
-
-License of code: GNU AGPL version 3
-License of media: CC-BY-SA 3.0
-
-(up to commit 1bb1d8, the license has been LGPL 2.1)
-
-Contributions:
-
-Coding:
-Various features and bugfixes have been contributed by:
-- gpcf
-- Blockhead
-- ywang
-Small code contributions:
-- h-v-smacker
-- NaruTrey
-
-Assets:
-Gravel Texture : from Minetest Game
-Initial rail model/texture : DS-minetest
-Models for signals/bumpers : mbb
-Steam engine / wagon texture: mbb
-Detailed Steam engine : mbb / Krokoschlange(animation)
-Industrial engine/wagons : mbb
-Inventory images : mbb
-Mod Description : hajo
-Sounds:
-advtrains_crossing_bell : Codesound
-advtrains_japan_horn : Codesound
-advtrains_steam_whistle : googol
-advtrains_subway_horn : https://freesound.org/people/Mullumbimby/sounds/385283/
-advtrains_subway_* : Gabriel (gbl08ma)
-45 degree platforms design : Och_Noe
-
-Testers:
-gpcf (Linuxworks server)
-imcasper (tss Branch)
-
-
-If I forgot someone please punish me for that. Also see the Git commit log.
-
-You can see this mod in action on Linuxworks Next Generation server.
diff --git a/serialize_lib/tests/serialize_spec.lua b/serialize_lib/spec/serialize_spec.lua
index ccc3a67..d4af8e2 100644
--- a/serialize_lib/tests/serialize_spec.lua
+++ b/serialize_lib/spec/serialize_spec.lua
@@ -10,7 +10,7 @@ ser = require("serialize")
local mock_file = {}
_G.mock_file = mock_file
function mock_file:read(arg)
- if arg == "*l" then
+ if arg == "*l" or arg== "*line" then
local l = self.lines[self.pointer or 1]
self.pointer = (self.pointer or 1) + 1
return l
@@ -49,7 +49,7 @@ local testtable = {
["es&&ca&\npe3"] = "baz&&bam&\nbim",
["es&:cape4"] = "foo\n:bar"
}
-local testser = [[LUA_SER v=1
+local testser = [[LUA_SER v=2
B1:T
Sa:Sb
Sc:B0
@@ -81,21 +81,18 @@ local function check_read(text)
return ser.read_from_fd(f)
end
-local noskip = [[LUA_SER v=1
+local noskip = [[LUA_SER v=2
N1:T
E
E
END_SER
]]
-local skip = [[LUA_SER v=1
+local skip = [[LUA_SER v=2
E
END_SER
]]
describe("write_to_fd", function()
- it("serializes a table correctly", function()
- assert.equals(check_write(testtable), testser)
- end)
it("does not skip empty tables", function()
assert.equals(check_write({{}}),noskip)
end)