charset=UTF-8 Last-Modified: Sun, 01 Nov 2026 15:31:12 GMT Expires: Wed, 29 Oct 2036 15:31:12 GMT Implementation Plan - advtrains.git - Advtrains mod for minetest.
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authororwell <orwell@bleipb.de>2024-01-28 23:42:56 +0100
committerorwell <orwell@bleipb.de>2024-01-28 23:42:56 +0100
commitaa9033f9010b01e7ad28f2b8bb0c002f065ddc08 (patch)
tree0cedd2279f3a506baf77866861e541d6d03bf9b4
parent5695a3e9ee457d8b0aa9ba03e7d73803d972a156 (diff)
Implementation Plan
-rw-r--r--advtrains_interlocking/signal_api.lua53
1 files changed, 53 insertions, 0 deletions
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
index ce8854a..743e8e1 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -19,6 +19,59 @@ advtrains.interlocking.FULL_FREE = {
proceed_as_main = true,
}
+--[[
+Implementation plan orwell 2024-01-28:
+Most parts of ywang's implementation are fine, especially I like the formspecs. But I would like to change a few aspects (no pun intended) of this.
+- Signal gets distant assigned via field in signal aspect table (instead of explicitly)
+- Signal speed/shunt are no longer free-text but rather they need to be predefined in the node definition
+To do this: Differentiation between:
+== Aspect Group ==
+This is what a signal is assigned by either the route system or the user.
+It is a string key which has an appropriate entry in the node definition (where it has a description assigned)
+The signal mod defines a function to set a signal to the most appropriate aspect. This function gets
+a) the aspect group name
+b) the distant signal's aspect group name & aspect table
+EVERY signal must define the special aspect group "halt". This must always be the most restrictive aspect possible.
+The "halt" aspect group should ignore any distant info, in most cases it is called without them anyway.
+
+== Aspect ==
+One concrete combination of lights/shapes that a signal signal shows. Handling these is at the discretion of
+the signal mod defining the signal, and they are typically combinations of main aspect and distant aspect
+Example:
+- A Ks signal has the aspect_group="proceed_12" set for a route
+- The signal at the end of the route shows aspect_group="proceed_8", advtrains also passes on that this means {main=8, shunt=false}
+- The ndef.advtrains.apply_aspect(pos, asp_group, dst_aspgrp, dst_aspinfo) determines that the signal should now show
+ blinking green with main indicator 12 and dst indicator 8, and sets the nodes accordingly.
+ This function can now return the Aspect Info table, which will be cached by advtrains until the aspect changes again
+ and will be used when a train approaches the signal. If nil is returned, then the aspect will be queried next time
+ by calling ndef.advtrains.get_aspect_info(pos)
+
+Note that once apply_aspect returns, there is no need for advtrains anymore to query the aspect info.
+When the signal, for any --clipboard = {trainlen = number, [n] = {type = string, flipped = bool, } -- Yaw is in radians. There are 2pi rad in a circle. North is the 0 point and the angle increases anticlockwise. -- 4.712389 = 1.5pi; sin(1.5pi) = -1 -- 7.853981 = 2.5pi; sin(2.5pi) = 1 minetest.register_tool("advtrains:copytool", { description = attrans("Train copy/paste tool\n\nLeft-click: copy train\nRight-click: paste train"), inventory_image = "advtrains_copytool.png", wield_image = "advtrains_copytool.png", stack_max = 1, -- Paste: Take the clipboard and the player yaw, and attempt to place a new train in the world. -- The front of the train is used as the start of the new train and it proceeds backwards from -- the direction of travel. on_place = function(itemstack, placer, pointed_thing) if ((not pointed_thing.type == "node") or (not placer.get_player_name)) then return end local pname = placer:get_player_name() local node=minetest.get_node_or_nil(pointed_thing.under) if not node then atprint("[advtrains]Ignore at placer position") return itemstack end local nodename=node.name if(not advtrains.is_track_and_drives_on(nodename, {default=true})) then atprint("no track here, not placing.") return itemstack end if not minetest.check_player_privs(placer, {train_operator = true }) then minetest.chat_send_player(pname, "You don't have the train_operator privilege.") return itemstack end if not minetest.check_player_privs(placer, {train_admin = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then return itemstack end local tconns=advtrains.get_track_connections(node.name, node.param2) local yaw = placer:get_look_horizontal() local plconnid = advtrains.yawToClosestConn(yaw, tconns) local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid, {default=true}) if not prevpos then minetest.chat_send_player(pname, "The track you are trying to place the wagon on is not long enough!") return end local meta = itemstack:get_meta() if not meta then minetest.chat_send_player(pname, attrans("The clipboard couldn't access the metadata. Paste failed.")) return end local clipboard = meta:get_string("clipboard") if (clipboard == "") then minetest.chat_send_player(pname, "The clipboard is empty."); return end clipboard = minetest.deserialize(clipboard) if (clipboard.wagons == nil) then minetest.chat_send_player(pname, "The clipboard is empty."); return end local wagons = {} local n = 1 for _, wagonProto in pairs(clipboard.wagons) do local wagon = advtrains.create_wagon(wagonProto.type, pname) advtrains.wagons[wagon].wagon_flipped = wagonProto.wagon_flipped wagons[n] = wagon n = n + 1 end local id=advtrains.create_new_train_at(pointed_thing.under, plconnid, 0, wagons) local train = advtrains.trains[id] train.off_track = train.end_index<train.path_trk_b if (train.off_track) then minetest.chat_send_player(pname, "Back of train would end up off track, cancelling.") advtrains.remove_train(id) return end train.text_outside = clipboard.text_outside train.text_inside = clipboard.text_inside train.routingcode = clipboard.routingcode train.line = clipboard.line return end, -- Copy: Take the pointed-at train and put it on the clipboard on_use = function(itemstack, user, pointed_thing) if not user:get_player_name() then return end if (pointed_thing.type ~= "object") then return end local le = pointed_thing.ref:get_luaentity() if (le == nil) then minetest.chat_send_player(user:get_player_name(), "No such lua entity!") return end local wagon = advtrains.wagons[le.id] if (not (le.id and advtrains.wagons[le.id])) then minetest.chat_send_player(user:get_player_name(), string.format("No such wagon: %s", le.id)) return end local train = advtrains.trains[wagon.train_id] if (not train) then minetest.chat_send_player(user:get_player_name(), string.format("No such train: %s", wagon.train_id)) return end -- Record the train length. The paste operation should require this much free space. local clipboard = { trainlen = math.ceil(train.trainlen), text_outside = train.text_outside, text_inside = train.text_inside, routingcode = train.routingcode, line = train.line, wagons = {} } local trainLength = math.ceil(train.trainlen) local n = 1 for _, wagonid in pairs(train.trainparts) do local wagon = advtrains.wagons[wagonid] clipboard.wagons[n] = { wagon_flipped = wagon.wagon_flipped, type = wagon.type } n = n + 1 end local function flip_clipboard(wagon_clipboard) local flipped = {} local numWagons = #wagon_clipboard for k, v in ipairs(wagon_clipboard) do local otherSide = (numWagons-k)+1 flipped[otherSide] = v local wagon = flipped[otherSide] wagon.wagon_flipped = not wagon.wagon_flipped end return flipped end local function is_loco(wagon_id) local wagon = advtrains.wagons[wagon_id] if (not wagon) then return false end local wagon_proto = advtrains.wagon_prototypes[wagon.type or wagon.entity_name] if wagon_proto and wagon_proto.is_locomotive then return true end return false end -- Decide on a new 'front of train' and possibly flip the train. -- Locomotive on one end = loco-hauled, that end is front; -- if (advtrains.wagons[train.trainparts[1]].is_locomotive) then -- do nothing, train is already in right order local numWagons = #train.trainparts local backLoco = train.trainparts[numWagons] backLoco = is_loco(backLoco) local frontLoco = train.trainparts[1] frontLoco = is_loco(frontLoco) if ((backLoco) and (not frontLoco)) then clipboard.wagons = flip_clipboard(clipboard.wagons) --minetest.chat_send_player(user:get_player_name(), "Flipped train: Loco-hauled") end -- locomotives on both ends = train is push-pull / multi-unit, has no front, do nothing -- no locomotives on ends = rake of wagons, front is end closest to where player copied. if ((not frontLoco) and (not backLoco)) then if (wagon.pos_in_trainparts / numWagons > 0.5) then -- towards the end of the rain clipboard.wagons = flip_clipboard(clipboard.wagons) --minetest.chat_send_player(user:get_player_name(), "Flipped train: Rake") end end local meta = itemstack:get_meta() if not meta then minetest.chat_send_player(pname, attrans("The clipboard couldn't access the metadata. Copy failed.")) return end meta:set_string("clipboard", minetest.serialize(clipboard)) minetest.chat_send_player(user:get_player_name(), attrans("Train copied!")) return itemstack end })