Fix final bugs and to-do's (u.a.save/load system)

master
orwell96 2018-05-29 12:27:02 +02:00
parent 254c32e304
commit 2a76d4a960
7 changed files with 100 additions and 180 deletions

View File

@ -34,7 +34,7 @@ minetest.register_entity("advtrains:discouple", {
return advtrains.pcall(function()
local pname = player:get_player_name()
if pname and pname~="" and self.wagon then
if self.wagon:safe_decouple(pname) then
if advtrains.safe_decouple_wagon(self.wagon.id, pname) then
self.object:remove()
else
minetest.add_entity(self.object:getpos(), "advtrains:lockmarker")
@ -53,7 +53,7 @@ minetest.register_entity("advtrains:discouple", {
self.object:remove()
return
end
if not self.wagon:train() and self.wagon:train().velocity > 0 then
if not self.wagon:train() or self.wagon:train().velocity > 0 then
self.object:remove()
return
end

View File

@ -37,7 +37,7 @@ advtrains.pos_add_dir = advtrains.dirCoordSet
function advtrains.pos_add_angle(pos, ang)
-- 0 is +Z -> meaning of sin/cos swapped
return vector.add(pos, {x = -math.cos(ang), y = 0, z = math.sin(ang)})
return vector.add(pos, {x = -math.sin(ang), y = 0, z = math.cos(ang)})
end
function advtrains.dirToCoord(dir)
@ -103,7 +103,7 @@ function advtrains.yawToClosestConn(yaw, conns)
local min_connid, min_diff=1, 10
for connid, conn in ipairs(conns) do
local yaw1 = advtrains.dir_to_angle(conn.c)
local diff = advtrains.minAngleDiffRad(yaw, yaw1)
local diff = math.abs(advtrains.minAngleDiffRad(yaw, yaw1))
if diff < min_diff then
min_connid = connid
min_diff = diff

View File

@ -41,14 +41,12 @@ function advtrains.pcall(fun)
local succ, return1, return2, return3, return4=xpcall(fun, function(err)
atwarn("Lua Error occured: ", err)
atwarn(debug.traceback())
if advtrains.atprint_context_tid_full then
advtrains.path_print(advtrains.trains[advtrains.atprint_context_tid_full], atdebug)
if advtrains.atprint_context_tid then
advtrains.path_print(advtrains.trains[advtrains.atprint_context_tid], atdebug)
end
end)
if not succ then
--reload_saves()
no_action=true --this does also not belong here!
minetest.request_shutdown()
reload_saves()
else
return return1, return2, return3, return4
end
@ -123,6 +121,7 @@ if minetest.settings:get_bool("advtrains_enable_debugging") then
--atlog("@@",advtrains.atprint_context_tid,t,...)
end
dofile(advtrains.modpath.."/debugringbuffer.lua")
end
function assertt(var, typ)
@ -185,7 +184,8 @@ dofile(advtrains.modpath.."/log.lua")
function advtrains.avt_load()
local file, err = io.open(advtrains.fpath, "r")
if not file then
minetest.log("error", " Failed to read advtrains save data from file "..advtrains.fpath..": "..(err or "Unknown Error"))
minetest.log("warning", " Failed to read advtrains save data from file "..advtrains.fpath..": "..(err or "Unknown Error"))
minetest.log("warning", " (this is normal when first enabling advtrains on this world)")
else
local tbl = minetest.deserialize(file:read("*a"))
if type(tbl) == "table" then
@ -196,7 +196,7 @@ function advtrains.avt_load()
for id, train in pairs(advtrains.trains) do
train.id = id
end
advtrains.wagon_save = tbl.wagon_save
advtrains.wagons = tbl.wagon_save
advtrains.player_to_train_mapping = tbl.ptmap or {}
advtrains.ndb.load_data(tbl.ndb)
advtrains.atc.load_data(tbl.atc)
@ -251,48 +251,30 @@ end
advtrains.avt_save = function(remove_players_from_wagons)
--atprint("saving")
--No more invalidating.
--Instead, remove path a.s.o from the saved table manually
-- update wagon saves
for _,wagon in pairs(minetest.luaentities) do
if wagon.is_wagon and wagon.initialized then
wagon:get_staticdata()
end
end
--cross out userdata
for w_id, data in pairs(advtrains.wagon_save) do
data.name=nil
data.object=nil
if data.driver then
data.driver_name=data.driver:get_player_name()
data.driver=nil
else
data.driver_name=nil
end
if data.discouple then
data.discouple.object:remove()
data.discouple=nil
end
if remove_players_from_wagons then
if remove_players_from_wagons then
for w_id, data in pairs(advtrains.wagons) do
data.seatp={}
end
end
if remove_players_from_wagons then
advtrains.player_to_train_mapping={}
end
local tmp_trains={}
for id, train in pairs(advtrains.trains) do
--first, deep_copy the train
local v=advtrains.save_keys(train, {
"last_pos", "last_pos_prev", "movedir", "velocity", "tarvelocity",
"trainparts", "savedpos_off_track_index_offset", "recently_collided_with_env",
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line"
})
--then save it
tmp_trains[id]=v
if #train.trainparts > 0 then
local v=advtrains.save_keys(train, {
"last_pos", "last_connid", "last_frac", "velocity", "tarvelocity",
"trainparts", "recently_collided_with_env",
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line"
})
--then save it
tmp_trains[id]=v
else
atwarn("Train",id,"had no wagons left because of some bug. It is being deleted. Wave it goodbye!")
advtrains.remove_train(id)
end
end
--versions:
@ -356,7 +338,7 @@ minetest.register_globalstep(function(dtime_mt)
if save_timer<=0 then
local t=os.clock()
--save
--advtrains.save()
advtrains.save()
save_timer=save_interval
atprintbm("saving", t)
end
@ -430,3 +412,4 @@ minetest.register_chatcommand("at_reroute",
local tot=(os.clock()-lot)*1000
minetest.log("action", "[advtrains] Loaded in "..tot.."ms")

View File

@ -172,9 +172,9 @@ function o.check_collision(pos, train_id)
if ti~=train_id then
local idx = t[i+1]
local train = advtrains.trains[ti]
atdebug("checking train",t[i],"index",idx,"<>",train.index,train.end_index)
--atdebug("checking train",t[i],"index",idx,"<>",train.index,train.end_index)
if idx >= train.end_index and idx <= train.index then
atdebug("collides.")
--atdebug("collides.")
return true
end
end
@ -190,7 +190,7 @@ end
function o.get_occupations(train, index)
local ppos, ontrack = advtrains.path_get(train, index)
if not ontrack then
atdebug("Train",train.id,"get_occupations requested off-track",index)
atwarn("Train",train.id,"get_occupations requested off-track",index)
return {}, ppos
end
local pos = advtrains.round_vector_floor_y(ppos)

View File

@ -1,76 +1,6 @@
-- path.lua
-- Functions for pathpredicting, put in a separate file.
function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return
local mid=advtrains.round_vector_floor_y(midreal)
local midnode_ok, midconns=advtrains.get_rail_info_at(mid, drives_on)
if not midnode_ok then
return nil
end
local pconnid
for connid, conn in ipairs(midconns) do
local tps = advtrains.dirCoordSet(mid, conn.c)
if tps.x==prev.x and tps.z==prev.z then
pconnid=connid
end
end
local nconnid = advtrains.get_matching_conn(pconnid, #midconns)
local next, next_connid, _, nextrailheight = advtrains.get_adjacent_rail(mid, midconns, nconnid, drives_on)
if not next then
return nil
end
return vector.add(advtrains.round_vector_floor_y(next), {x=0, y=nextrailheight, z=0}), midconns[nconnid].c
end
function advtrains.pathpredict(id, train, gen_front, gen_back)
local maxn=train.path_extent_max or 0
while maxn < gen_front do--pregenerate
local conway
if train.max_index_on_track == maxn then
--atprint("maxn conway for ",maxn,train.path[maxn],maxn-1,train.path[maxn-1])
conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.drives_on)
end
if conway then
train.path[maxn+1]=conway
train.max_index_on_track=maxn+1
else
--do as if nothing has happened and preceed with path
--but do not update max_index_on_track
atprint("over-generating path max to index ",(maxn+1)," (position ",train.path[maxn]," )")
train.path[maxn+1]=vector.add(train.path[maxn], vector.subtract(train.path[maxn], train.path[maxn-1]))
end
train.path_dist[maxn]=vector.distance(train.path[maxn+1], train.path[maxn])
maxn=maxn+1
end
train.path_extent_max=maxn
local minn=train.path_extent_min or -1
while minn > gen_back do
local conway
if train.min_index_on_track == minn then
--atprint("minn conway for ",minn,train.path[minn],minn+1,train.path[minn+1])
conway=advtrains.conway(train.path[minn], train.path[minn+1], train.drives_on)
end
if conway then
train.path[minn-1]=conway
train.min_index_on_track=minn-1
else
--do as if nothing has happened and preceed with path
--but do not update min_index_on_track
atprint("over-generating path min to index ",(minn-1)," (position ",train.path[minn]," )")
train.path[minn-1]=vector.add(train.path[minn], vector.subtract(train.path[minn], train.path[minn+1]))
end
train.path_dist[minn-1]=vector.distance(train.path[minn], train.path[minn-1])
minn=minn-1
end
train.path_extent_min=minn
if not train.min_index_on_track then train.min_index_on_track=-1 end
if not train.max_index_on_track then train.max_index_on_track=0 end
end
-- Naming conventions:
-- 'index' - An index of the train.path table.
-- 'offset' - A value in meters that determines how far on the path to walk relative to a certain index
@ -145,7 +75,7 @@ function advtrains.path_setrestore(train, invert)
end
-- Get restore position, connid and frac (in this order) for a train that will originate at the passed index
-- If invert is set, it will return path_cp and multiply frac by -1, in order to reverse the train there.
function advtrains.path_getrestore(train, index, invert, tmp)
function advtrains.path_getrestore(train, index, invert)
local idx = index
local cns = train.path_cn
@ -153,7 +83,7 @@ function advtrains.path_getrestore(train, index, invert, tmp)
cns = train.path_cp
end
fli = atfloor(index)
local fli = atfloor(index)
advtrains.path_get(train, fli)
if fli > train.path_trk_f then
fli = train.path_trk_f
@ -161,9 +91,6 @@ function advtrains.path_getrestore(train, index, invert, tmp)
if fli < train.path_trk_b then
fli = train.path_trk_b
end
if not tmp then
atdebug ("getrestore ",atround(train.index),"calc",atround(index),fli)
end
return advtrains.path_get(train, fli),
cns[fli],
(idx - fli) * (invert and -1 or 1)
@ -195,7 +122,13 @@ end
function advtrains.path_print(train, printf)
printf("i: CP Position Dir CN ->Dist->")
for i = train.path_ext_b, train.path_ext_f do
if i==train.path_trk_b then
printf("--Back on-track border here--")
end
printf(i,": ",train.path_cp[i]," ",train.path[i]," ",train.path_dir[i]," ",train.path_cn[i]," ->",train.path_dist[i],"->")
if i==train.path_trk_f then
printf("--Front on-track border here--")
end
end
end
@ -231,6 +164,7 @@ function advtrains.path_get(train, index)
else
-- off-track fallback behavior
adj_pos = advtrains.pos_add_angle(pos, train.path_dir[pef-1])
--atdebug("Offtrack overgenerating(front) at",adj_pos,"index",peb,"trkf",train.path_trk_f)
train.path_dir[pef] = train.path_dir[pef-1]
end
train.path[pef] = adj_pos
@ -260,6 +194,7 @@ function advtrains.path_get(train, index)
else
-- off-track fallback behavior
adj_pos = advtrains.pos_add_angle(pos, train.path_dir[peb+1] + math.pi)
--atdebug("Offtrack overgenerating(back) at",adj_pos,"index",peb,"trkb",train.path_trk_b)
train.path_dir[peb] = train.path_dir[peb+1]
end
train.path[peb] = adj_pos
@ -326,7 +261,6 @@ function advtrains.path_get_index_by_offset(train, index, offset)
idx = idx - 1
advtrains.path_get_adjacent(train, idx)
if not train.path_dist[idx] then
atdebug("second while",idx)
for i=-5,5 do
atdebug(idx+i,train.path_dist[idx+i])
end
@ -363,6 +297,8 @@ function advtrains.path_clear_unused(train)
train.path_dir[i+1] = nil
train.path_ext_f = i - 1
end
train.path_trk_b = math.max(train.path_trk_b, train.path_ext_b)
train.path_trk_f = math.min(train.path_trk_f, train.path_ext_f)
train.path_req_f = math.ceil(train.index)
train.path_req_b = math.floor(train.end_index or train.index)

View File

@ -1,7 +1,6 @@
--trainlogic.lua
--controls train entities stuff about connecting/disconnecting/colliding trains and other things
-- TODO: what should happen when a train has no trainparts anymore?
local benchmark=false
local bm={}
@ -68,17 +67,17 @@ advtrains.mainloop_trainlogic=function(dtime)
local t=os.clock()
for k,v in pairs(advtrains.trains) do
advtrains.atprint_context_tid=sid(k)
advtrains.atprint_context_tid=k
advtrains.train_ensure_init(k, v)
end
for k,v in pairs(advtrains.trains) do
advtrains.atprint_context_tid=sid(k)
advtrains.atprint_context_tid=k
advtrains.train_step_b(k, v, dtime)
end
for k,v in pairs(advtrains.trains) do
advtrains.atprint_context_tid=sid(k)
advtrains.atprint_context_tid=k
advtrains.train_step_c(k, v, dtime)
end
@ -242,7 +241,7 @@ function advtrains.train_ensure_init(id, train)
advtrains.update_trainpart_properties(id)
recalc_end_index(train)
atdebug("Train",id,": Successfully restored path at",train.last_pos," connid",train.last_connid," frac",train.last_frac)
--atdebug("Train",id,": Successfully restored path at",train.last_pos," connid",train.last_connid," frac",train.last_frac)
-- run on_new_path callbacks
run_callbacks_new_path(id, train)
@ -470,8 +469,7 @@ end
-- asserted to rely on this)
local function tnc_call_enter_callback(pos, train_id)
--atprint("instructed to call enter calback")
--atdebug("tnc enter",pos,train_id)
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
local mregnode=minetest.registered_nodes[node.name]
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_enter then
@ -479,8 +477,7 @@ local function tnc_call_enter_callback(pos, train_id)
end
end
local function tnc_call_leave_callback(pos, train_id)
--atprint("instructed to call leave calback")
--atdebug("tnc leave",pos,train_id)
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
local mregnode=minetest.registered_nodes[node.name]
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_leave then
@ -493,7 +490,7 @@ advtrains.te_register_on_new_path(function(id, train)
old_index = atround(train.index),
old_end_index = atround(train.end_index),
}
atdebug(id,"tnc init",train.index,train.end_index)
--atdebug(id,"tnc init",train.index,train.end_index)
end)
advtrains.te_register_on_update(function(id, train)
@ -523,7 +520,7 @@ advtrains.te_register_on_create(function(id, train)
tnc_call_enter_callback(pos, id)
end_index = end_index + 1
end
atdebug(id,"tnc create",train.index,train.end_index)
--atdebug(id,"tnc create",train.index,train.end_index)
end)
advtrains.te_register_on_remove(function(id, train)
@ -534,7 +531,7 @@ advtrains.te_register_on_remove(function(id, train)
tnc_call_leave_callback(pos, id)
end_index = end_index + 1
end
atdebug(id,"tnc remove",train.index,train.end_index)
--atdebug(id,"tnc remove",train.index,train.end_index)
end)
-- Calculates the indices where the window borders of the occupation windows are.
@ -570,8 +567,6 @@ local function calc_occwindows(id, train)
}
end
--TODO: Collisions!
--returns new id
function advtrains.create_new_train_at(pos, connid, ioff, trainparts)
@ -590,7 +585,7 @@ function advtrains.create_new_train_at(pos, connid, ioff, trainparts)
t.trainparts=trainparts
advtrains.trains[new_id] = t
atdebug("Created new train:",t)
--atdebug("Created new train:",t)
advtrains.train_ensure_init(new_id, advtrains.trains[new_id])
@ -610,7 +605,7 @@ function advtrains.remove_train(id)
advtrains.couple_invalidate(train)
local tp = train.trainparts
atdebug("Removing train",id,"leftover trainparts:",tp)
--atdebug("Removing train",id,"leftover trainparts:",tp)
advtrains.trains[id] = nil
@ -635,6 +630,23 @@ function advtrains.add_wagon_to_train(wagon_id, train_id, index)
run_callbacks_update(train_id, train)
end
function advtrains.safe_decouple_wagon(w_id, pname)
if not minetest.check_player_privs(pname, "train_operator") then
minetest.chat_send_player(pname, "Missing train_operator privilege")
return false
end
local data = advtrains.wagons[w_id]
if data.dcpl_lock then
minetest.chat_send_player(pname, "Couple is locked (ask owner or admin to unlock it)")
return false
end
atprint("wagon:discouple() Splitting train", data.train_id)
local train = advtrains.trains[data.train_id]
advtrains.log("Discouple", pname, train.last_pos, train.text_outside)
advtrains.split_train_at_wagon(w_id)
return true
end
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more)
function advtrains.update_trainpart_properties(train_id, invert_flipstate)
local train=advtrains.trains[train_id]
@ -692,14 +704,15 @@ local ablkrng = minetest.settings:get("active_block_range")*16
function advtrains.spawn_wagons(train_id)
local train = advtrains.trains[train_id]
for i, w_id in ipairs(train.trainparts) do
for i = 1, #train.trainparts do
local w_id = train.trainparts[i]
local data = advtrains.wagons[w_id]
if data then
if data.train_id ~= train_id then
atwarn("Train",train_id,"Wagon #",1,": Saved train ID",data.train_id,"did not match!")
data.train_id = train_id
end
if not data.object or not data.object:getyaw() then
if not advtrains.wagon_objects[w_id] or not advtrains.wagon_objects[w_id]:getyaw() then
-- eventually need to spawn new object. check if position is loaded.
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
local pos = advtrains.path_get(train, atfloor(index))
@ -717,6 +730,10 @@ function advtrains.spawn_wagons(train_id)
wagon:set_id(w_id)
end
end
else
atwarn("Train",train_id,"Wagon #",1,": A wagon with id",w_id,"does not exist! Wagon will be removed from train.")
table.remove(train.trainparts, i)
i = i - 1
end
end
end
@ -745,6 +762,11 @@ function advtrains.split_train_at_wagon(wagon_id)
end
end
--update train parts
advtrains.update_trainpart_properties(old_id)
recalc_end_index(train)
run_callbacks_update(old_id, train)
--create subtrain
local newtrain_id=advtrains.create_new_train_at(pos, connid, frac, tp)
local newtrain=advtrains.trains[newtrain_id]
@ -757,11 +779,6 @@ function advtrains.split_train_at_wagon(wagon_id)
newtrain.couple_lck_front=false
train.couple_lck_back=false
--update train parts
advtrains.update_trainpart_properties(old_id)
recalc_end_index(train)
run_callbacks_update(old_id, train)
end
-- coupling
@ -778,7 +795,7 @@ local function createcouple(pos, train1, t1_is_front, train2, t2_is_front)
le.train_id_2=train2.id
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)
--atdebug("created couple between",train1.id,t1_is_front,train2.id,t2_is_front)
if t1_is_front then
train1.cpl_front = obj
else
@ -793,7 +810,7 @@ local function createcouple(pos, train1, t1_is_front, train2, t2_is_front)
end
function advtrains.train_check_couples(train)
atdebug("rechecking couples")
--atdebug("rechecking couples")
if train.cpl_front then
if not train.cpl_front:getyaw() then
-- objectref is no longer valid. reset.
@ -806,7 +823,7 @@ function advtrains.train_check_couples(train)
for tid, idx in pairs(front_trains) do
local other_train = advtrains.trains[tid]
advtrains.train_ensure_init(tid, other_train)
atdebug(train.id,"front: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
--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)
@ -924,8 +941,12 @@ function advtrains.invert_train(train_id)
advtrains.update_trainpart_properties(train_id, true)
end
-- returns: train id, index of one of the trains that stand at this position.
function advtrains.get_train_at_pos(pos)
return advtrains.occ.get_trains_at(pos)[1]
local t = advtrains.occ.get_trains_at(pos)
for tid,idx in pairs(t) do
return tid, idx
end
end
function advtrains.invalidate_all_paths(pos)

View File

@ -9,6 +9,7 @@
advtrains.wagons = {}
advtrains.wagon_prototypes = {}
advtrains.wagon_objects = {}
--
function advtrains.create_wagon(wtype, owner)
@ -21,7 +22,7 @@ function advtrains.create_wagon(wtype, owner)
wgn.id = new_id
---wgn.train_id = train_id --- will get this via update_trainpart_properties
advtrains.wagons[new_id] = wgn
atdebug("Created new wagon:",wgn)
--atdebug("Created new wagon:",wgn)
return new_id
end
@ -60,9 +61,9 @@ function wagon:set_id(wid)
self.initialized = true
local data = advtrains.wagons[self.id]
advtrains.wagon_objects[self.id] = self.object
data.object = self.object
atdebug("Created wagon entity:",self.name," w_id",wid," t_id",data.train_id)
--atdebug("Created wagon entity:",self.name," w_id",wid," t_id",data.train_id)
if self.has_inventory then
--to be used later
@ -196,7 +197,7 @@ function wagon:destroy()
if self.discouple then self.discouple.object:remove() end--will have no effect on unloaded objects
end
end
atdebug("[wagon ", self.id, "]: destroying")
--atdebug("[wagon ", self.id, "]: destroying")
self.object:remove()
end
@ -210,7 +211,7 @@ function wagon:on_step(dtime)
local data = advtrains.wagons[self.id]
if not pos then
atdebug("["..self.id.."][fatal] missing position (object:getpos() returned nil)")
--atdebug("["..self.id.."][fatal] missing position (object:getpos() returned nil)")
return
end
@ -437,7 +438,6 @@ function wagon:on_step(dtime)
else
train.recently_collided_with_env=true
train.velocity=0
-- TODO what should happen when a train collides?
train.tarvelocity=0
self.collision_count=(self.collision_count or 0)+1
end
@ -852,11 +852,7 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
end
for i, tpid in ipairs(train.trainparts) do
if fields["dcpl_"..i] then
for _,wagon in pairs(minetest.luaentities) do
if wagon.is_wagon and wagon.initialized and wagon.id==tpid then
wagon:safe_decouple(pname) -- TODO: Move this into external function (don't search entity?)
end
end
advtrains.safe_decouple_wagon(tpid, pname)
end
if i>1 and fields["dcpl_lck_"..i] then
local ent = advtrains.wagons[tpid]
@ -1026,26 +1022,10 @@ function wagon:reattach_all()
end
end
function wagon:safe_decouple(pname)
if not minetest.check_player_privs(pname, "train_operator") then
minetest.chat_send_player(pname, "Missing train_operator privilege")
return false
end
local data = advtrains.wagons[self.id]
if data.dcpl_lock then
minetest.chat_send_player(pname, "Couple is locked (ask owner or admin to unlock it)")
return false
end
atprint("wagon:discouple() Splitting train", self.train_id)
advtrains.log("Discouple", pname, self.object:getpos(), self:train().text_outside)
advtrains.split_train_at_wagon(self.id)--found in trainlogic.lua
return true
end
function advtrains.get_wagon_prototype(data)
local wt = data.type
if not advtrains.wagon_prototypes[wt] then
atprint("Unable to load wagon type",wt,", using placeholder")
if not data.type or not advtrains.wagon_prototypes[wt] then
atwarn("Unable to load wagon type",wt,", using placeholder")
wt="advtrains:wagon_placeholder"
end
return wt, advtrains.wagon_prototypes[wt]