diff options
| -rw-r--r-- | advtrains.zip | bin | 4992304 -> 4992868 bytes | |||
| -rw-r--r-- | advtrains/advtrains/atc.lua | 86 | ||||
| -rw-r--r-- | advtrains/advtrains/couple.lua | 228 | ||||
| -rw-r--r-- | advtrains/advtrains/init.lua | 168 | ||||
| -rw-r--r-- | advtrains/advtrains/nodedb.lua | 54 | ||||
| -rw-r--r-- | advtrains/advtrains/trackplacer.lua | 166 | ||||
| -rw-r--r-- | advtrains/advtrains/trainlogic.lua | 91 | ||||
| -rw-r--r-- | advtrains/advtrains/wagons.lua | 873 | ||||
| -rw-r--r-- | advtrains/advtrains_itrainmap/init.lua | 10 | ||||
| -rw-r--r-- | advtrains/advtrains_luaautomation/init.lua | 50 | ||||
| -rw-r--r-- | advtrains/advtrains_luaautomation/interrupt.lua | 37 | 
11 files changed, 897 insertions, 866 deletions
| diff --git a/advtrains.zip b/advtrains.zipBinary files differ index eb47749..2144e28 100644 --- a/advtrains.zip +++ b/advtrains.zip diff --git a/advtrains/advtrains/atc.lua b/advtrains/advtrains/atc.lua index 577f858..ed631a3 100644 --- a/advtrains/advtrains/atc.lua +++ b/advtrains/advtrains/atc.lua @@ -92,55 +92,53 @@ advtrains.register_tracks("default", {  		return {  			after_place_node=apn_func,  			after_dig_node=function(pos) -			return advtrains.pcall(function() - -				advtrains.invalidate_all_paths() -				advtrains.ndb.clear(pos) -				local pts=minetest.pos_to_string(pos) -				atc.controllers[pts]=nil -			end) +				return advtrains.pcall(function() +					advtrains.invalidate_all_paths() +					advtrains.ndb.clear(pos) +					local pts=minetest.pos_to_string(pos) +					atc.controllers[pts]=nil +				end)  			end,  			on_receive_fields = function(pos, formname, fields, player) -			return advtrains.pcall(function() - -				if advtrains.is_protected(pos, player:get_player_name()) then -					minetest.record_protection_violation(pos, player:get_player_name()) -					return -				end -				local meta=minetest.get_meta(pos) -				if meta then -					if not fields.save then  -						--maybe only the dropdown changed -						if fields.mode then -							meta:set_string("mode", idxtrans[fields.mode]) -							if fields.mode=="digiline" then -								meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) ) -							else -								meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) ) -							end -							meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) -						end +				return advtrains.pcall(function() +					if advtrains.is_protected(pos, player:get_player_name()) then +						minetest.record_protection_violation(pos, player:get_player_name())  						return  					end -					meta:set_string("mode", idxtrans[fields.mode]) -					meta:set_string("command", fields.command) -					meta:set_string("command_on", fields.command_on) -					meta:set_string("channel", fields.channel) -					if fields.mode=="digiline" then -						meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) ) -					else -						meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) ) -					end -					meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) -					 -					local pts=minetest.pos_to_string(pos) -					local _, conn1=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) -					atc.controllers[pts]={command=fields.command, arrowconn=conn1} -					if advtrains.detector.on_node[pts] then -						atc.send_command(pos) +					local meta=minetest.get_meta(pos) +					if meta then +						if not fields.save then  +							--maybe only the dropdown changed +							if fields.mode then +								meta:set_string("mode", idxtrans[fields.mode]) +								if fields.mode=="digiline" then +									meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) ) +								else +									meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) ) +								end +								meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) +							end +							return +						end +						meta:set_string("mode", idxtrans[fields.mode]) +						meta:set_string("command", fields.command) +						meta:set_string("command_on", fields.command_on) +						meta:set_string("channel", fields.channel) +						if fields.mode=="digiline" then +							meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) ) +						else +							meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) ) +						end +						meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) +						 +						local pts=minetest.pos_to_string(pos) +						local _, conn1=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) +						atc.controllers[pts]={command=fields.command, arrowconn=conn1} +						if advtrains.detector.on_node[pts] then +							atc.send_command(pos) +						end  					end -				end -			end) +				end)  			end,  			advtrains = {  				on_train_enter = function(pos, train_id) diff --git a/advtrains/advtrains/couple.lua b/advtrains/advtrains/couple.lua index 3693e84..ac4dfce 100644 --- a/advtrains/advtrains/couple.lua +++ b/advtrains/advtrains/couple.lua @@ -31,58 +31,56 @@ minetest.register_entity("advtrains:discouple", {  	end,  	get_staticdata=function() return "DISCOUPLE" end,  	on_punch=function(self, player) -	return advtrains.pcall(function() - -		--only if player owns at least one wagon next to this -		local own=player:get_player_name() -		if self.wagon.owner and self.wagon.owner==own and not self.wagon.lock_couples then -			local train=advtrains.trains[self.wagon.train_id] -			local nextwgn_id=train.trainparts[self.wagon.pos_in_trainparts-1] -			for aoi, le in pairs(minetest.luaentities) do -				if le and le.is_wagon then -					if le.unique_id==nextwgn_id then -						if le.owner and le.owner~=own then -							minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple.")) -							return +		return advtrains.pcall(function() +			--only if player owns at least one wagon next to this +			local own=player:get_player_name() +			if self.wagon.owner and self.wagon.owner==own and not self.wagon.lock_couples then +				local train=advtrains.trains[self.wagon.train_id] +				local nextwgn_id=train.trainparts[self.wagon.pos_in_trainparts-1] +				for aoi, le in pairs(minetest.luaentities) do +					if le and le.is_wagon then +						if le.unique_id==nextwgn_id then +							if le.owner and le.owner~=own then +								minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple.")) +								return +							end  						end  					end  				end +				atprint("Discouple punched. Splitting train", self.wagon.train_id) +				advtrains.split_train_at_wagon(self.wagon)--found in trainlogic.lua +				self.object:remove() +			elseif self.wagon.lock_couples then +				minetest.chat_send_player(own, "Couples of one of the wagons are locked, can't discouple!") +			else +				minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))  			end -			atprint("Discouple punched. Splitting train", self.wagon.train_id) -			advtrains.split_train_at_wagon(self.wagon)--found in trainlogic.lua -			self.object:remove() -		elseif self.wagon.lock_couples then -			minetest.chat_send_player(own, "Couples of one of the wagons are locked, can't discouple!") -		else -			minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple.")) -		end -	end) +		end)  	end,  	on_step=function(self, dtime) -	return advtrains.pcall(function() - -		local t=os.clock() -		if not self.wagon then -			self.object:remove() -			atprint("Discouple: no wagon, destroying") -			return -		end -		--getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not. -		if not self.wagon.object:getyaw() then -			atprint("Discouple: wagon no longer loaded, destroying") -			self.object:remove() -			return -		end -		local velocityvec=self.wagon.object:getvelocity() -		self.updatepct_timer=(self.updatepct_timer or 0)-dtime -		if not self.old_velocity_vector or not vector.equals(velocityvec, self.old_velocity_vector) or self.updatepct_timer<=0 then--only send update packet if something changed -			local flipsign=self.wagon.wagon_flipped and -1 or 1 -			self.object:setpos(vector.add(self.wagon.object:getpos(), {y=0, x=-math.sin(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign, z=math.cos(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign})) -			self.object:setvelocity(velocityvec) -			self.updatepct_timer=2 -		end -		atprintbm("discouple_step", t) -	end) +		return advtrains.pcall(function() +			local t=os.clock() +			if not self.wagon then +				self.object:remove() +				atprint("Discouple: no wagon, destroying") +				return +			end +			--getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not. +			if not self.wagon.object:getyaw() then +				atprint("Discouple: wagon no longer loaded, destroying") +				self.object:remove() +				return +			end +			local velocityvec=self.wagon.object:getvelocity() +			self.updatepct_timer=(self.updatepct_timer or 0)-dtime +			if not self.old_velocity_vector or not vector.equals(velocityvec, self.old_velocity_vector) or self.updatepct_timer<=0 then--only send update packet if something changed +				local flipsign=self.wagon.wagon_flipped and -1 or 1 +				self.object:setpos(vector.add(self.wagon.object:getpos(), {y=0, x=-math.sin(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign, z=math.cos(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign})) +				self.object:setvelocity(velocityvec) +				self.updatepct_timer=2 +			end +			atprintbm("discouple_step", t) +		end)  	end,  }) @@ -105,82 +103,78 @@ minetest.register_entity("advtrains:couple", {  	is_couple=true,  	on_activate=function(self, staticdata) -	return advtrains.pcall(function() - -		if staticdata=="COUPLE" then -			--couple entities have no right to exist further... -			atprint("Couple loaded from staticdata, destroying") -			self.object:remove() -			return -		end -	end) +		return advtrains.pcall(function() +			if staticdata=="COUPLE" then +				--couple entities have no right to exist further... +				atprint("Couple loaded from staticdata, destroying") +				self.object:remove() +				return +			end +		end)  	end,  	get_staticdata=function(self) return "COUPLE" end,  	on_rightclick=function(self, clicker) -	return advtrains.pcall(function() - -		if not self.train_id_1 or not self.train_id_2 then return end -		 -		local id1, id2=self.train_id_1, self.train_id_2 -		 -		if self.train1_is_backpos and not self.train2_is_backpos then -			advtrains.do_connect_trains(id1, id2, clicker) -			--case 2 (second train is front) -		elseif self.train2_is_backpos and not self.train1_is_backpos then -			advtrains.do_connect_trains(id2, id1, clicker) -			--case 3  -		elseif self.train1_is_backpos and self.train2_is_backpos then -			advtrains.invert_train(id2) -			advtrains.do_connect_trains(id1, id2, clicker) -			--case 4  -		elseif not self.train1_is_backpos and not self.train2_is_backpos then -			advtrains.invert_train(id1) -			advtrains.do_connect_trains(id1, id2, clicker) -		end -		atprint("Coupled trains", id1, id2) -		self.object:remove() -	end) +		return advtrains.pcall(function() +			if not self.train_id_1 or not self.train_id_2 then return end +			 +			local id1, id2=self.train_id_1, self.train_id_2 +			if self.train1_is_backpos and not self.train2_is_backpos then +				advtrains.do_connect_trains(id1, id2, clicker) +				--case 2 (second train is front) +			elseif self.train2_is_backpos and not self.train1_is_backpos then +				advtrains.do_connect_trains(id2, id1, clicker) +				--case 3  +			elseif self.train1_is_backpos and self.train2_is_backpos then +				advtrains.invert_train(id2) +				advtrains.do_connect_trains(id1, id2, clicker) +				--case 4  +			elseif not self.train1_is_backpos and not self.train2_is_backpos then +				advtrains.invert_train(id1) +				advtrains.do_connect_trains(id1, id2, clicker) +			end +			atprint("Coupled trains", id1, id2) +			self.object:remove() +		end)  	end,  	on_step=function(self, dtime) -	return advtrains.pcall(function() - -		local t=os.clock() -		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 -		if not train1.path or not train2.path or not train1.index or not train2.index or not train1.end_index or not train2.end_index then -			atprint("Couple: paths or end_index missing. Might happen when paths got cleared") -			return -		end -		 -		local tp1 -		if not self.train1_is_backpos then -			tp1=advtrains.get_real_index_position(train1.path, train1.index) -		else -			tp1=advtrains.get_real_index_position(train1.path, train1.end_index) -		end -		local tp2 -		if not self.train2_is_backpos then -			tp2=advtrains.get_real_index_position(train2.path, train2.index) -		else -			tp2=advtrains.get_real_index_position(train2.path, train2.end_index) -		end -		if not tp1 or not tp2 or not (vector.distance(tp1,tp2)<couple_max_dist) then -			atprint("Couple: train end positions too distanced, destroying") -			self.object:remove() -			return -		else -			local pos_median=advtrains.pos_median(tp1, tp2) -			if not vector.equals(pos_median, self.object:getpos()) then -				self.object:setpos(pos_median) +		return advtrains.pcall(function() +			local t=os.clock() +			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 -		end -		atprintbm("couple step", t) -	end) +			if not train1.path or not train2.path or not train1.index or not train2.index or not train1.end_index or not train2.end_index then +				atprint("Couple: paths or end_index missing. Might happen when paths got cleared") +				return +			end +			 +			local tp1 +			if not self.train1_is_backpos then +				tp1=advtrains.get_real_index_position(train1.path, train1.index) +			else +				tp1=advtrains.get_real_index_position(train1.path, train1.end_index) +			end +			local tp2 +			if not self.train2_is_backpos then +				tp2=advtrains.get_real_index_position(train2.path, train2.index) +			else +				tp2=advtrains.get_real_index_position(train2.path, train2.end_index) +			end +			if not tp1 or not tp2 or not (vector.distance(tp1,tp2)<couple_max_dist) then +				atprint("Couple: train end positions too distanced, destroying") +				self.object:remove() +				return +			else +				local pos_median=advtrains.pos_median(tp1, tp2) +				if not vector.equals(pos_median, self.object:getpos()) then +					self.object:setpos(pos_median) +				end +			end +			atprintbm("couple step", t) +		end)  	end,  })  diff --git a/advtrains/advtrains/init.lua b/advtrains/advtrains/init.lua index 9b7f31f..022fcee 100644 --- a/advtrains/advtrains/init.lua +++ b/advtrains/advtrains/init.lua @@ -10,7 +10,7 @@ end  advtrains = {trains={}, wagon_save={}, player_to_train_mapping={}}  --pcall -local no_action=true +local no_action=false  function advtrains.pcall(fun)  	if no_action then return end @@ -118,62 +118,58 @@ dofile(advtrains.modpath.."/craft_items.lua")  advtrains.fpath=minetest.get_worldpath().."/advtrains" -function advtrains.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")) -else -	local tbl = minetest.deserialize(file:read("*a")) -	if type(tbl) == "table" then -		if tbl.version then -			--congrats, we have the new save format. -			advtrains.trains = tbl.trains -			advtrains.wagon_save = tbl.wagon_save -			advtrains.player_to_train_mapping = tbl.ptmap or {} -			advtrains.ndb.load_data(tbl.ndb) -			advtrains.atc.load_data(tbl.atc) -		else -			--oh no, its the old one... -			advtrains.trains=tbl -			--load ATC -			advtrains.fpath_atc=minetest.get_worldpath().."/advtrains_atc" -			local file, err = io.open(advtrains.fpath_atc, "r") -			if not file then -				local er=err or "Unknown Error" -				atprint("Failed loading advtrains atc save file "..er) +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")) +	else +		local tbl = minetest.deserialize(file:read("*a")) +		if type(tbl) == "table" then +			if tbl.version then +				--congrats, we have the new save format. +				advtrains.trains = tbl.trains +				advtrains.wagon_save = tbl.wagon_save +				advtrains.player_to_train_mapping = tbl.ptmap or {} +				advtrains.ndb.load_data(tbl.ndb) +				advtrains.atc.load_data(tbl.atc)  			else -				local tbl = minetest.deserialize(file:read("*a")) -				if type(tbl) == "table" then -					advtrains.atc.controllers=tbl.controllers +				--oh no, its the old one... +				advtrains.trains=tbl +				--load ATC +				advtrains.fpath_atc=minetest.get_worldpath().."/advtrains_atc" +				local file, err = io.open(advtrains.fpath_atc, "r") +				if not file then +					local er=err or "Unknown Error" +					atprint("Failed loading advtrains atc save file "..er) +				else +					local tbl = minetest.deserialize(file:read("*a")) +					if type(tbl) == "table" then +						advtrains.atc.controllers=tbl.controllers +					end +					file:close()  				end -				file:close() -			end -			--load wagon saves -			advtrains.fpath_ws=minetest.get_worldpath().."/advtrains_wagon_save" -			local file, err = io.open(advtrains.fpath_ws, "r") -			if not file then -				local er=err or "Unknown Error" -				atprint("Failed loading advtrains save file "..er) -			else -				local tbl = minetest.deserialize(file:read("*a")) -				if type(tbl) == "table" then -					advtrains.wagon_save=tbl +				--load wagon saves +				advtrains.fpath_ws=minetest.get_worldpath().."/advtrains_wagon_save" +				local file, err = io.open(advtrains.fpath_ws, "r") +				if not file then +					local er=err or "Unknown Error" +					atprint("Failed loading advtrains save file "..er) +				else +					local tbl = minetest.deserialize(file:read("*a")) +					if type(tbl) == "table" then +						advtrains.wagon_save=tbl +					end +					file:close()  				end -				file:close()  			end +		else +			minetest.log("error", " Failed to deserialize advtrains save data: Not a table!")  		end -	else -		minetest.log("error", " Failed to deserialize advtrains save data: Not a table!") +		file:close()  	end -	file:close()  end -no_action=false -end -advtrains.load() - -advtrains.save = function() +advtrains.avt_save = function()  	--atprint("saving")  	advtrains.invalidate_all_paths() @@ -222,4 +218,78 @@ advtrains.save = function()  	file:write(datastr)  	file:close()  end + +--## MAIN LOOP ##-- +--Calls all subsequent main tasks of both advtrains and atlatc +local init_load=false +local save_interval=20 +local save_timer=save_interval + +minetest.register_globalstep(function(dtime_mt) +	return advtrains.pcall(function() +		--call load once. see advtrains.load() comment +		if not init_load then +			advtrains.load() +		end +		--limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains +		local dtime=dtime_mt +		if dtime>0.2 then +			atprint("Limiting dtime to 0.2!") +			dtime=0.2 +		end +		 +		advtrains.mainloop_trainlogic(dtime) +		if advtrains_itm_mainloop then +			advtrains_itm_mainloop(dtime) +		end +		if atlatc then +			atlatc.mainloop_stepcode(dtime) +			atlatc.interrupt.mainloop(dtime) +		end +		 +		 +		--trigger a save when necessary +		save_timer=save_timer-dtime +		if save_timer<=0 then +			local t=os.clock() +			--save +			advtrains.save() +			save_timer=save_interval +			atprintbm("saving", t) +		end +	end) +end) + +--if something goes wrong in these functions, there is no help. no pcall here. + +--## MAIN LOAD ROUTINE ## +-- Causes the loading of everything +-- first time called in main loop (after the init phase) because luaautomation has to initialize first. +function advtrains.load() +	advtrains.avt_load() --loading advtrains. includes ndb at advtrains.ndb.load_data() +	if atlatc then +		atlatc.load() --includes interrupts +	end +	if advtrains_itm_init then +		advtrains_itm_init() +	end +	init_load=true +	no_action=false +	atprint("[load_all]Loaded advtrains save files") +end + +--## MAIN SAVE ROUTINE ## +-- Causes the saving of everything +function advtrains.save() +	if not init_load then +		--wait... we haven't loaded yet?! +		atwarn("Instructed to save() but load() was never called!") +		return +	end +	advtrains.avt_save() --saving advtrains. includes ndb at advtrains.ndb.save_data() +	if atlatc then +		atlatc.save() +	end +	atprint("[save_all]Saved advtrains save files") +end  minetest.register_on_shutdown(advtrains.save) diff --git a/advtrains/advtrains/nodedb.lua b/advtrains/advtrains/nodedb.lua index 2fb3656..55adea8 100644 --- a/advtrains/advtrains/nodedb.lua +++ b/advtrains/advtrains/nodedb.lua @@ -203,43 +203,41 @@ minetest.register_abm({          nodenames = {"group:save_in_nodedb"},          run_at_every_load = true,          action = function(pos, node) -        return advtrains.pcall(function() - -			local cid=ndbget(pos.x, pos.y, pos.z) -			if cid then -				--if in database, detect changes and apply. -				local nodeid = ndb_nodeids[u14b(cid)] -				local param2 = l2b(cid) -				if not nodeid then -					--something went wrong -					atprint("nodedb: lbm nid not found", pos, "with nid", u14b(cid), "param2", param2, "cid is", cid) -					ndb.update(pos, node) -				else -					if (nodeid~=node.name or param2~=node.param2) then -						atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid) -						minetest.swap_node(pos, {name=nodeid, param2 = param2}) -						local ndef=minetest.registered_nodes[nodeid] -						if ndef and ndef.on_updated_from_nodedb then -							ndef.on_updated_from_nodedb(pos, node) +			return advtrains.pcall(function() +				local cid=ndbget(pos.x, pos.y, pos.z) +				if cid then +					--if in database, detect changes and apply. +					local nodeid = ndb_nodeids[u14b(cid)] +					local param2 = l2b(cid) +					if not nodeid then +						--something went wrong +						atprint("nodedb: lbm nid not found", pos, "with nid", u14b(cid), "param2", param2, "cid is", cid) +						ndb.update(pos, node) +					else +						if (nodeid~=node.name or param2~=node.param2) then +							atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid) +							minetest.swap_node(pos, {name=nodeid, param2 = param2}) +							local ndef=minetest.registered_nodes[nodeid] +							if ndef and ndef.on_updated_from_nodedb then +								ndef.on_updated_from_nodedb(pos, node) +							end  						end  					end +				else +					--if not in database, take it. +					atprint("nodedb: ", pos, "not in database") +					ndb.update(pos, node)  				end -			else -				--if not in database, take it. -				atprint("nodedb: ", pos, "not in database") -				ndb.update(pos, node) -			end -		end) +			end)          end,          interval=10,          chance=1,      })  minetest.register_on_dignode(function(pos, oldnode, digger) -return advtrains.pcall(function() - -	ndb.clear(pos) -end) +	return advtrains.pcall(function() +		ndb.clear(pos) +	end)  end)  function ndb.get_nodes() diff --git a/advtrains/advtrains/trackplacer.lua b/advtrains/advtrains/trackplacer.lua index 5f9bdf7..105b77e 100644 --- a/advtrains/advtrains/trackplacer.lua +++ b/advtrains/advtrains/trackplacer.lua @@ -187,29 +187,28 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname)  		wield_image = imgprefix.."_placer.png",  		groups={},  		on_place = function(itemstack, placer, pointed_thing) -		return advtrains.pcall(function() - -		        local name = placer:get_player_name() -			if not name then -			   return itemstack -			end -			if pointed_thing.type=="node" then -				local pos=pointed_thing.above -				local upos=vector.subtract(pointed_thing.above, {x=0, y=1, z=0}) -				if advtrains.is_protected(pos,name) then -					minetest.record_protection_violation(pos, name) -					return itemstack +			return advtrains.pcall(function() +					local name = placer:get_player_name() +				if not name then +				   return itemstack  				end -				if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to -					and minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable then -					tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing) -					if not minetest.setting_getbool("creative_mode") then -						itemstack:take_item() +				if pointed_thing.type=="node" then +					local pos=pointed_thing.above +					local upos=vector.subtract(pointed_thing.above, {x=0, y=1, z=0}) +					if advtrains.is_protected(pos,name) then +						minetest.record_protection_violation(pos, name) +						return itemstack +					end +					if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to +						and minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable then +						tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing) +						if not minetest.setting_getbool("creative_mode") then +							itemstack:take_item() +						end  					end  				end -			end -			return itemstack -		end) +				return itemstack +			end)  		end,  	})  end @@ -223,83 +222,82 @@ minetest.register_craftitem("advtrains:trackworker",{  	wield_image = "advtrains_trackworker.png",  	stack_max = 1,  	on_place = function(itemstack, placer, pointed_thing) -	return advtrains.pcall(function() -		local name = placer:get_player_name() -		if not name then -			return -		end -		if pointed_thing.type=="node" then -			local pos=pointed_thing.under -			if advtrains.is_protected(pos, name) then -				minetest.record_protection_violation(pos, name) +		return advtrains.pcall(function() +			local name = placer:get_player_name() +			if not name then  				return  			end -			local node=minetest.get_node(pos) +			if pointed_thing.type=="node" then +				local pos=pointed_thing.under +				if advtrains.is_protected(pos, name) then +					minetest.record_protection_violation(pos, name) +					return +				end +				local node=minetest.get_node(pos) -			--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end -			if advtrains.get_train_at_pos(pos) then return end +				--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end +				if advtrains.get_train_at_pos(pos) then return end -			local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") -			--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation) -			if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then -				nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$") -				rotation = "" +				local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") +				--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)  				if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then -					minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!")) -					return +					nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$") +					rotation = "" +					if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then +						minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!")) +						return +					end  				end -			end -			local modext=tp.tracks[nnprefix].twrotate[suffix] +				local modext=tp.tracks[nnprefix].twrotate[suffix] -			if rotation==modext[#modext] then --increase param2 -				advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4}) -				return -			else -				local modpos -				for k,v in pairs(modext) do if v==rotation then modpos=k end end -					if not modpos then -						minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!")) +				if rotation==modext[#modext] then --increase param2 +					advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4})  					return +				else +					local modpos +					for k,v in pairs(modext) do if v==rotation then modpos=k end end +						if not modpos then +							minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!")) +						return +					end +					advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})  				end -				advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})  			end -		end -	end) +		end)  	end,  	on_use=function(itemstack, user, pointed_thing) -	return advtrains.pcall(function() - -	        local name = user:get_player_name() -		if not name then -		   return -		end -		if pointed_thing.type=="node" then -			local pos=pointed_thing.under -			local node=minetest.get_node(pos) -			if advtrains.is_protected(pos, name) then -			    minetest.record_protection_violation(pos, name) -				return +		return advtrains.pcall(function() +				local name = user:get_player_name() +			if not name then +			   return  			end -			 -			--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end -			if advtrains.get_train_at_pos(pos) then return end -			local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") -	        --atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation) -		    if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then -			  nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$") -			  rotation = "" -			  if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then -			    minetest.chat_send_player(user:get_player_name(), attrans("This node can't be changed using the trackworker!")) -			    return -			  end -		    end -			local nextsuffix=tp.tracks[nnprefix].twcycle[suffix] -			advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2}) -			 -		else -			atprint(name, dump(tp.tracks)) -		end -	end) +			if pointed_thing.type=="node" then +				local pos=pointed_thing.under +				local node=minetest.get_node(pos) +				if advtrains.is_protected(pos, name) then +					minetest.record_protection_violation(pos, name) +					return +				end +				 +				--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end +				if advtrains.get_train_at_pos(pos) then return end +				local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") +				--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation) +				if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then +				  nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$") +				  rotation = "" +				  if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then +					minetest.chat_send_player(user:get_player_name(), attrans("This node can't be changed using the trackworker!")) +					return +				  end +				end +				local nextsuffix=tp.tracks[nnprefix].twcycle[suffix] +				advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2}) +				 +			else +				atprint(name, dump(tp.tracks)) +			end +		end)  	end,  }) diff --git a/advtrains/advtrains/trainlogic.lua b/advtrains/advtrains/trainlogic.lua index 0caea0b..7dad80c 100644 --- a/advtrains/advtrains/trainlogic.lua +++ b/advtrains/advtrains/trainlogic.lua @@ -36,27 +36,8 @@ advtrains.train_brake_force=3--per second, not divided by number of wagons  advtrains.train_roll_force=0.5--per second, not divided by number of wagons, acceleration when rolling without brake  advtrains.train_emerg_force=10--for emergency brakes(when going off track) -advtrains.save_interval=10 -advtrains.save_timer=advtrains.save_interval -minetest.register_globalstep(function(dtime_mt) -return advtrains.pcall(function() - -	--limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains -	local dtime=dtime_mt -	if dtime>0.2 then -		atprint("Limiting dtime to 0.2!") -		dtime=0.2 -	end - -	advtrains.save_timer=advtrains.save_timer-dtime -	if advtrains.save_timer<=0 then -		local t=os.clock() -		--save -		advtrains.save() -		advtrains.save_timer=advtrains.save_interval -		atprintbm("saving", t) -	end +advtrains.mainloop_trainlogic=function(dtime)  	--build a table of all players indexed by pts. used by damage and door system.  	advtrains.playersbypts={}  	for _, player in pairs(minetest.get_connected_players()) do @@ -82,49 +63,46 @@ return advtrains.pcall(function()  	atprintbm("trainsteps", t)  	endstep() -end) -end) +end  minetest.register_on_joinplayer(function(player) -return advtrains.pcall(function() - -	local pname=player:get_player_name() -	local id=advtrains.player_to_train_mapping[pname] -	if id then -		local train=advtrains.trains[id] -		if not train then advtrains.player_to_train_mapping[pname]=nil return end -		--set the player to the train position. -		--minetest will emerge the area and load the objects, which then will call reattach_all(). -		--because player is in mapping, it will not be subject to dying. -		player:setpos(train.last_pos_prev) -		--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() -		for _,wagon in pairs(minetest.luaentities) do -			if wagon.is_wagon and wagon.initialized and wagon.train_id==id then -				wagon:reattach_all() +	return advtrains.pcall(function() +		local pname=player:get_player_name() +		local id=advtrains.player_to_train_mapping[pname] +		if id then +			local train=advtrains.trains[id] +			if not train then advtrains.player_to_train_mapping[pname]=nil return end +			--set the player to the train position. +			--minetest will emerge the area and load the objects, which then will call reattach_all(). +			--because player is in mapping, it will not be subject to dying. +			player:setpos(train.last_pos_prev) +			--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() +			for _,wagon in pairs(minetest.luaentities) do +				if wagon.is_wagon and wagon.initialized and wagon.train_id==id then +					wagon:reattach_all() +				end  			end  		end -	end -end) +	end)  end)  minetest.register_on_dieplayer(function(player) -return advtrains.pcall(function() - -	local pname=player:get_player_name() -	local id=advtrains.player_to_train_mapping[pname] -	if id then -		local train=advtrains.trains[id] -		if not train then advtrains.player_to_train_mapping[pname]=nil return end -		for _,wagon in pairs(minetest.luaentities) do -			if wagon.is_wagon and wagon.initialized and wagon.train_id==id then -				--when player dies, detach him from the train -				--call get_off_plr on every wagon since we don't know which one he's on. -				wagon:get_off_plr(pname) +	return advtrains.pcall(function() +		local pname=player:get_player_name() +		local id=advtrains.player_to_train_mapping[pname] +		if id then +			local train=advtrains.trains[id] +			if not train then advtrains.player_to_train_mapping[pname]=nil return end +			for _,wagon in pairs(minetest.luaentities) do +				if wagon.is_wagon and wagon.initialized and wagon.train_id==id then +					--when player dies, detach him from the train +					--call get_off_plr on every wagon since we don't know which one he's on. +					wagon:get_off_plr(pname) +				end  			end  		end -	end -end) +	end)  end)  --[[  train step structure: @@ -822,6 +800,10 @@ end  function advtrains.do_connect_trains(first_id, second_id, player)  	local first, second=advtrains.trains[first_id], advtrains.trains[second_id] +	if not first or not second or not first.index or not second.index or not first.end_index or not second.end_index then +		return false +	end +	  	if first.couple_lock_back or second.couple_lock_front then  		-- trains are ordered correctly!  		if player then @@ -842,6 +824,7 @@ function advtrains.do_connect_trains(first_id, second_id, player)  	advtrains.update_trainpart_properties(first_id)  	advtrains.trains[first_id].velocity=new_velocity  	advtrains.trains[first_id].tarvelocity=0 +	return true  end  function advtrains.invert_train(train_id) diff --git a/advtrains/advtrains/wagons.lua b/advtrains/advtrains/wagons.lua index 2ceea86..3325879 100644 --- a/advtrains/advtrains/wagons.lua +++ b/advtrains/advtrains/wagons.lua @@ -50,21 +50,21 @@ function wagon:on_activate(sd_uid, dtime_s)  end
  function wagon:get_staticdata()
 -return advtrains.pcall(function()
 -	if not self:ensure_init() then return end
 -	atprint("[wagon "..((self.unique_id and self.unique_id~="" and self.unique_id) or "no-id").."]: saving to wagon_save")
 -	--serialize inventory, if it has one
 -	if self.has_inventory then
 -		local inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..self.unique_id})
 -		self.ser_inv=advtrains.serialize_inventory(inv)
 -	end
 -	--save to table before being unloaded
 -	advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self)
 -	advtrains.wagon_save[self.unique_id].entity_name=self.name
 -	advtrains.wagon_save[self.unique_id].name=nil
 -	advtrains.wagon_save[self.unique_id].object=nil
 -	return self.unique_id
 -end)
 +	return advtrains.pcall(function()
 +		if not self:ensure_init() then return end
 +		atprint("[wagon "..((self.unique_id and self.unique_id~="" and self.unique_id) or "no-id").."]: saving to wagon_save")
 +		--serialize inventory, if it has one
 +		if self.has_inventory then
 +			local inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..self.unique_id})
 +			self.ser_inv=advtrains.serialize_inventory(inv)
 +		end
 +		--save to table before being unloaded
 +		advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self)
 +		advtrains.wagon_save[self.unique_id].entity_name=self.name
 +		advtrains.wagon_save[self.unique_id].name=nil
 +		advtrains.wagon_save[self.unique_id].object=nil
 +		return self.unique_id
 +	end)
  end
  --returns: uid of wagon
  function wagon:init_new_instance(train_id, properties)
 @@ -149,38 +149,38 @@ end  -- Remove the wagon
  function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
 -return advtrains.pcall(function()
 -	if not self:ensure_init() then return end
 -	if not puncher or not puncher:is_player() then
 -		return
 -	end
 -	if self.owner and puncher:get_player_name()~=self.owner and (not minetest.check_player_privs(puncher, {train_remove = true })) then
 -	   minetest.chat_send_player(puncher:get_player_name(), attrans("This wagon is owned by @1, you can't destroy it.", self.owner));
 -	   return
 -	end
 -	
 -	if minetest.setting_getbool("creative_mode") then
 -		if not self:destroy() then return end
 -		
 -		local inv = puncher:get_inventory()
 -		if not inv:contains_item("main", self.name) then
 -			inv:add_item("main", self.name)
 -		end
 -	else
 -		local pc=puncher:get_player_control()
 -		if not pc.sneak then
 -			minetest.chat_send_player(puncher:get_player_name(), attrans("Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon."))
 +	return advtrains.pcall(function()
 +		if not self:ensure_init() then return end
 +		if not puncher or not puncher:is_player() then
  			return
  		end
 +		if self.owner and puncher:get_player_name()~=self.owner and (not minetest.check_player_privs(puncher, {train_remove = true })) then
 +		   minetest.chat_send_player(puncher:get_player_name(), attrans("This wagon is owned by @1, you can't destroy it.", self.owner));
 +		   return
 +		end
 +		
 +		if minetest.setting_getbool("creative_mode") then
 +			if not self:destroy() then return end
 +			
 +			local inv = puncher:get_inventory()
 +			if not inv:contains_item("main", self.name) then
 +				inv:add_item("main", self.name)
 +			end
 +		else
 +			local pc=puncher:get_player_control()
 +			if not pc.sneak then
 +				minetest.chat_send_player(puncher:get_player_name(), attrans("Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon."))
 +				return
 +			end
 -		if not self:destroy() then return end
 +			if not self:destroy() then return end
 -		local inv = puncher:get_inventory()
 -		for _,item in ipairs(self.drops or {self.name}) do
 -			inv:add_item("main", item)
 +			local inv = puncher:get_inventory()
 +			for _,item in ipairs(self.drops or {self.name}) do
 +				inv:add_item("main", item)
 +			end
  		end
 -	end
 -end)
 +	end)
  end
  function wagon:destroy()
  	--some rules:
 @@ -215,263 +215,262 @@ end  function wagon:on_step(dtime)
 -return advtrains.pcall(function()
 -
 -	if not self:ensure_init() then return end
 -	
 -	local t=os.clock()
 -	local pos = self.object:getpos()
 -	
 -	if not pos then
 -		atprint("["..self.unique_id.."][fatal] missing position (object:getpos() returned nil)")
 -		return
 -	end
 +	return advtrains.pcall(function()
 +		if not self:ensure_init() then return end
 +		
 +		local t=os.clock()
 +		local pos = self.object:getpos()
 +		
 +		if not pos then
 +			atprint("["..self.unique_id.."][fatal] missing position (object:getpos() returned nil)")
 +			return
 +		end
 -	self.entity_name=self.name
 -	
 -	--is my train still here
 -	if not self.train_id or not self:train() then
 -		atprint("[wagon "..self.unique_id.."] missing train_id, destroying")
 -		self.object:remove()
 -		return
 -	end
 -	if not self.seatp then
 -		self.seatp={}
 -	end
 -	if not self.seatpc then
 -		self.seatpc={}
 -	end
 -	
 -	--Legacy: remove infotext since it does not work this way anyways
 -	self.infotext=nil
 +		self.entity_name=self.name
 +		
 +		--is my train still here
 +		if not self.train_id or not self:train() then
 +			atprint("[wagon "..self.unique_id.."] missing train_id, destroying")
 +			self.object:remove()
 +			return
 +		end
 +		if not self.seatp then
 +			self.seatp={}
 +		end
 +		if not self.seatpc then
 +			self.seatpc={}
 +		end
 +		
 +		--Legacy: remove infotext since it does not work this way anyways
 +		self.infotext=nil
 -	--custom on_step function
 -	if self.custom_on_step then
 -		self:custom_on_step(self, dtime)
 -	end
 +		--custom on_step function
 +		if self.custom_on_step then
 +			self:custom_on_step(self, dtime)
 +		end
 -	--driver control
 -	for seatno, seat in ipairs(self.seats) do
 -		local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
 -		local has_driverstand=seat.driving_ctrl_access and self.seatp[seatno] and minetest.check_player_privs(self.seatp[seatno], {train_operator=true})
 -		if has_driverstand and driver then
 -			advtrains.update_driver_hud(driver:get_player_name(), self:train(), self.wagon_flipped)
 -		elseif driver then
 -			--only show the inside text
 -			local inside=self:train().text_inside or ""
 -			advtrains.set_trainhud(driver:get_player_name(), inside)
 -		end
 -		if driver and driver:get_player_control_bits()~=self.seatpc[seatno] then
 -			local pc=driver:get_player_control()
 -			self.seatpc[seatno]=driver:get_player_control_bits()
 -			
 -			if has_driverstand then
 -				--regular driver stand controls
 -				advtrains.on_control_change(pc, self:train(), self.wagon_flipped)
 -			else
 -				-- If on a passenger seat and doors are open, get off when W or D pressed.
 -				local pass = self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
 -				if pass and self:train().door_open~=0 then
 -				local pc=pass:get_player_control()
 -					if pc.up or pc.down then
 -						self:get_off(seatno)
 -					end
 -				end		      
 -			end
 -			if pc.aux1 and pc.sneak then
 -				self:get_off(seatno)
 +		--driver control
 +		for seatno, seat in ipairs(self.seats) do
 +			local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
 +			local has_driverstand=seat.driving_ctrl_access and self.seatp[seatno] and minetest.check_player_privs(self.seatp[seatno], {train_operator=true})
 +			if has_driverstand and driver then
 +				advtrains.update_driver_hud(driver:get_player_name(), self:train(), self.wagon_flipped)
 +			elseif driver then
 +				--only show the inside text
 +				local inside=self:train().text_inside or ""
 +				advtrains.set_trainhud(driver:get_player_name(), inside)
  			end
 -		end
 -	end
 -	
 -	--check infotext
 -	local outside=self:train().text_outside or ""
 -	if self.object:get_properties().infotext~=outside then
 -		self.object:set_properties({infotext=outside})
 -	end
 -	
 -	local gp=self:train()
 -	local fct=self.wagon_flipped and -1 or 1
 -	--door animation
 -	if self.doors then
 -		if (self.door_anim_timer or 0)<=0 then
 -			local dstate = (gp.door_open or 0) * fct
 -			if dstate ~= self.door_state then
 -				local at
 -				--meaning of the train.door_open field:
 -				-- -1: left doors (rel. to train orientation)
 -				--  0: closed
 -				--  1: right doors
 -				--this code produces the following behavior:
 -				-- if changed from 0 to +-1, play open anim. if changed from +-1 to 0, play close.
 -				-- if changed from +-1 to -+1, first close and set 0, then it will detect state change again and run open.
 -				if self.door_state == 0 then
 -					at=self.doors.open[dstate]
 -					self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
 -					self.door_state = dstate
 +			if driver and driver:get_player_control_bits()~=self.seatpc[seatno] then
 +				local pc=driver:get_player_control()
 +				self.seatpc[seatno]=driver:get_player_control_bits()
 +				
 +				if has_driverstand then
 +					--regular driver stand controls
 +					advtrains.on_control_change(pc, self:train(), self.wagon_flipped)
  				else
 -					at=self.doors.close[self.door_state or 1]--in case it has not been set yet
 -					self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
 -					self.door_state = 0
 +					-- If on a passenger seat and doors are open, get off when W or D pressed.
 +					local pass = self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
 +					if pass and self:train().door_open~=0 then
 +					local pc=pass:get_player_control()
 +						if pc.up or pc.down then
 +							self:get_off(seatno)
 +						end
 +					end		      
 +				end
 +				if pc.aux1 and pc.sneak then
 +					self:get_off(seatno)
  				end
 -				self.door_anim_timer = at.time
  			end
 -		else
 -			self.door_anim_timer = (self.door_anim_timer or 0) - dtime
  		end
 -	end
 -	
 -	--DisCouple
 -	if self.pos_in_trainparts and self.pos_in_trainparts>1 then
 -		if gp.velocity==0 and not self.lock_couples then
 -			if not self.discouple or not self.discouple.object:getyaw() then
 -				local object=minetest.add_entity(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
 -				else
 -					atprint("Couldn't spawn DisCouple")
 +		
 +		--check infotext
 +		local outside=self:train().text_outside or ""
 +		if self.object:get_properties().infotext~=outside then
 +			self.object:set_properties({infotext=outside})
 +		end
 +		
 +		local gp=self:train()
 +		local fct=self.wagon_flipped and -1 or 1
 +		--door animation
 +		if self.doors then
 +			if (self.door_anim_timer or 0)<=0 then
 +				local dstate = (gp.door_open or 0) * fct
 +				if dstate ~= self.door_state then
 +					local at
 +					--meaning of the train.door_open field:
 +					-- -1: left doors (rel. to train orientation)
 +					--  0: closed
 +					--  1: right doors
 +					--this code produces the following behavior:
 +					-- if changed from 0 to +-1, play open anim. if changed from +-1 to 0, play close.
 +					-- if changed from +-1 to -+1, first close and set 0, then it will detect state change again and run open.
 +					if self.door_state == 0 then
 +						at=self.doors.open[dstate]
 +						self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
 +						self.door_state = dstate
 +					else
 +						at=self.doors.close[self.door_state or 1]--in case it has not been set yet
 +						self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
 +						self.door_state = 0
 +					end
 +					self.door_anim_timer = at.time
  				end
 -			end
 -		else
 -			if self.discouple and self.discouple.object:getyaw() then
 -				self.discouple.object:remove()
 +			else
 +				self.door_anim_timer = (self.door_anim_timer or 0) - dtime
  			end
  		end
 -	end
 -	--for path to be available. if not, skip step
 -	if not gp.path then
 -		self.object:setvelocity({x=0, y=0, z=0})
 -		return
 -	end
 -	if not self.pos_in_train then
 -		--why ever. but better continue next step...
 -		advtrains.update_trainpart_properties(self.train_id)
 -		return
 -	end
 -	
 -	local index=advtrains.get_real_path_index(self:train(), self.pos_in_train)
 -	--atprint("trainindex "..gp.index.." wagonindex "..index)
 -	
 -	--automatic get_on
 -	--needs to know index and path
 -	if self.door_entry and gp.door_open and gp.door_open~=0 and gp.velocity==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
 -			local aci = index + ino*fct
 -			local ix1=gp.path[math.floor(aci)]
 -			local ix2=gp.path[math.floor(aci+1)]
 -			-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
 -			-- (x z) rotated by 90deg is (-z x)  (http://stackoverflow.com/a/4780141)
 -			local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
 -			local pts1=vector.round(vector.add(ix1, add))
 -			local pts2=vector.round(vector.add(ix2, add))
 -			if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
 -				local ckpts={
 -					pts1,
 -					pts2,
 -					vector.add(pts1, {x=0, y=1, z=0}),
 -					vector.add(pts2, {x=0, y=1, z=0}),
 -				}
 -				for _,ckpos in ipairs(ckpts) do
 -					local cpp=minetest.pos_to_string(ckpos)
 -					if advtrains.playersbypts[cpp] then
 -						self:on_rightclick(advtrains.playersbypts[cpp])
 +		
 +		--DisCouple
 +		if self.pos_in_trainparts and self.pos_in_trainparts>1 then
 +			if gp.velocity==0 and not self.lock_couples then
 +				if not self.discouple or not self.discouple.object:getyaw() then
 +					local object=minetest.add_entity(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
 +					else
 +						atprint("Couldn't spawn DisCouple")
  					end
  				end
 +			else
 +				if self.discouple and self.discouple.object:getyaw() then
 +					self.discouple.object:remove()
 +				end
  			end
  		end
 -	end
 -	
 -	--position recalculation
 -	local first_pos=gp.path[math.floor(index)]
 -	local second_pos=gp.path[math.floor(index)+1]
 -	if not first_pos or not second_pos then
 -		--atprint(" object "..self.unique_id.." path end reached!")
 -		self.object:setvelocity({x=0,y=0,z=0})
 -		return
 -	end
 -	
 -	--checking for environment collisions(a 3x3 cube around the center)
 -	if not gp.recently_collided_with_env then
 -		local collides=false
 -		for x=-1,1 do
 -			for y=0,2 do
 -				for z=-1,1 do
 -					local node=minetest.get_node_or_nil(vector.add(first_pos, {x=x, y=y, z=z}))
 -					if (advtrains.train_collides(node)) then
 -						collides=true
 +		--for path to be available. if not, skip step
 +		if not gp.path then
 +			self.object:setvelocity({x=0, y=0, z=0})
 +			return
 +		end
 +		if not self.pos_in_train then
 +			--why ever. but better continue next step...
 +			advtrains.update_trainpart_properties(self.train_id)
 +			return
 +		end
 +		
 +		local index=advtrains.get_real_path_index(self:train(), self.pos_in_train)
 +		--atprint("trainindex "..gp.index.." wagonindex "..index)
 +		
 +		--automatic get_on
 +		--needs to know index and path
 +		if self.door_entry and gp.door_open and gp.door_open~=0 and gp.velocity==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
 +				local aci = index + ino*fct
 +				local ix1=gp.path[math.floor(aci)]
 +				local ix2=gp.path[math.floor(aci+1)]
 +				-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
 +				-- (x z) rotated by 90deg is (-z x)  (http://stackoverflow.com/a/4780141)
 +				local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
 +				local pts1=vector.round(vector.add(ix1, add))
 +				local pts2=vector.round(vector.add(ix2, add))
 +				if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
 +					local ckpts={
 +						pts1,
 +						pts2,
 +						vector.add(pts1, {x=0, y=1, z=0}),
 +						vector.add(pts2, {x=0, y=1, z=0}),
 +					}
 +					for _,ckpos in ipairs(ckpts) do
 +						local cpp=minetest.pos_to_string(ckpos)
 +						if advtrains.playersbypts[cpp] then
 +							self:on_rightclick(advtrains.playersbypts[cpp])
 +						end
  					end
  				end
  			end
  		end
 -		if collides then
 -			if self.collision_count and self.collision_count>10 then
 -				--enable collision mercy to get trains stuck in walls out of walls
 -				--actually do nothing except limiting the velocity to 1
 -				gp.velocity=math.min(gp.velocity, 1)
 -				gp.tarvelocity=math.min(gp.tarvelocity, 1)
 +		
 +		--position recalculation
 +		local first_pos=gp.path[math.floor(index)]
 +		local second_pos=gp.path[math.floor(index)+1]
 +		if not first_pos or not second_pos then
 +			--atprint(" object "..self.unique_id.." path end reached!")
 +			self.object:setvelocity({x=0,y=0,z=0})
 +			return
 +		end
 +		
 +		--checking for environment collisions(a 3x3 cube around the center)
 +		if not gp.recently_collided_with_env then
 +			local collides=false
 +			for x=-1,1 do
 +				for y=0,2 do
 +					for z=-1,1 do
 +						local node=minetest.get_node_or_nil(vector.add(first_pos, {x=x, y=y, z=z}))
 +						if (advtrains.train_collides(node)) then
 +							collides=true
 +						end
 +					end
 +				end
 +			end
 +			if collides then
 +				if self.collision_count and self.collision_count>10 then
 +					--enable collision mercy to get trains stuck in walls out of walls
 +					--actually do nothing except limiting the velocity to 1
 +					gp.velocity=math.min(gp.velocity, 1)
 +					gp.tarvelocity=math.min(gp.tarvelocity, 1)
 +				else
 +					gp.recently_collided_with_env=true
 +					gp.velocity=2*gp.velocity
 +					gp.movedir=-gp.movedir
 +					gp.tarvelocity=0
 +					self.collision_count=(self.collision_count or 0)+1
 +				end
  			else
 -				gp.recently_collided_with_env=true
 -				gp.velocity=2*gp.velocity
 -				gp.movedir=-gp.movedir
 -				gp.tarvelocity=0
 -				self.collision_count=(self.collision_count or 0)+1
 +				self.collision_count=nil
  			end
 +		end
 +		
 +		--FIX: use index of the wagon, not of the train.
 +		local velocity=(gp.velocity*gp.movedir)/(gp.path_dist[math.floor(index)] or 1)
 +		local acceleration=(gp.last_accel or 0)/(gp.path_dist[math.floor(index)] or 1)
 +		local factor=index-math.floor(index)
 +		local actual_pos={x=first_pos.x-(first_pos.x-second_pos.x)*factor, y=first_pos.y-(first_pos.y-second_pos.y)*factor, z=first_pos.z-(first_pos.z-second_pos.z)*factor,}
 +		local velocityvec={x=(first_pos.x-second_pos.x)*velocity*-1, z=(first_pos.z-second_pos.z)*velocity*-1, y=(first_pos.y-second_pos.y)*velocity*-1}
 +		local accelerationvec={x=(first_pos.x-second_pos.x)*acceleration*-1, z=(first_pos.z-second_pos.z)*acceleration*-1, y=(first_pos.y-second_pos.y)*acceleration*-1}
 +		
 +		--some additional positions to determine orientation
 +		local aposfwd=gp.path[math.floor(index+2)]
 +		local aposbwd=gp.path[math.floor(index-1)]
 +		
 +		local yaw
 +		if aposfwd and aposbwd then
 +			yaw=advtrains.get_wagon_yaw(aposfwd, second_pos, first_pos, aposbwd, factor)+math.pi--TODO remove when cleaning up
  		else
 -			self.collision_count=nil
 +			yaw=math.atan2((first_pos.x-second_pos.x), (second_pos.z-first_pos.z))
  		end
 -	end
 -	
 -	--FIX: use index of the wagon, not of the train.
 -	local velocity=(gp.velocity*gp.movedir)/(gp.path_dist[math.floor(index)] or 1)
 -	local acceleration=(gp.last_accel or 0)/(gp.path_dist[math.floor(index)] or 1)
 -	local factor=index-math.floor(index)
 -	local actual_pos={x=first_pos.x-(first_pos.x-second_pos.x)*factor, y=first_pos.y-(first_pos.y-second_pos.y)*factor, z=first_pos.z-(first_pos.z-second_pos.z)*factor,}
 -	local velocityvec={x=(first_pos.x-second_pos.x)*velocity*-1, z=(first_pos.z-second_pos.z)*velocity*-1, y=(first_pos.y-second_pos.y)*velocity*-1}
 -	local accelerationvec={x=(first_pos.x-second_pos.x)*acceleration*-1, z=(first_pos.z-second_pos.z)*acceleration*-1, y=(first_pos.y-second_pos.y)*acceleration*-1}
 -	
 -	--some additional positions to determine orientation
 -	local aposfwd=gp.path[math.floor(index+2)]
 -	local aposbwd=gp.path[math.floor(index-1)]
 -	
 -	local yaw
 -	if aposfwd and aposbwd then
 -		yaw=advtrains.get_wagon_yaw(aposfwd, second_pos, first_pos, aposbwd, factor)+math.pi--TODO remove when cleaning up
 -	else
 -		yaw=math.atan2((first_pos.x-second_pos.x), (second_pos.z-first_pos.z))
 -	end
 -	if self.wagon_flipped then
 -		yaw=yaw+math.pi
 -	end
 -	
 -	self.updatepct_timer=(self.updatepct_timer or 0)-dtime
 -	if not self.old_velocity_vector 
 -			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.updatepct_timer<=0 then--only send update packet if something changed
 -			self.object:setpos(actual_pos)
 -		self.object:setvelocity(velocityvec)
 -		self.object:setacceleration(accelerationvec)
 -		self.object:setyaw(yaw)
 -		self.updatepct_timer=2
 -		if self.update_animation then
 -			self:update_animation(gp.velocity)
 +		if self.wagon_flipped then
 +			yaw=yaw+math.pi
  		end
 -	end
 -	
 -	
 -	self.old_velocity_vector=velocityvec
 -	self.old_acceleration_vector=accelerationvec
 -	self.old_yaw=yaw
 -	atprintbm("wagon step", t)
 -end)
 +		
 +		self.updatepct_timer=(self.updatepct_timer or 0)-dtime
 +		if not self.old_velocity_vector 
 +				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.updatepct_timer<=0 then--only send update packet if something changed
 +				self.object:setpos(actual_pos)
 +			self.object:setvelocity(velocityvec)
 +			self.object:setacceleration(accelerationvec)
 +			self.object:setyaw(yaw)
 +			self.updatepct_timer=2
 +			if self.update_animation then
 +				self:update_animation(gp.velocity)
 +			end
 +		end
 +		
 +		
 +		self.old_velocity_vector=velocityvec
 +		self.old_acceleration_vector=accelerationvec
 +		self.old_yaw=yaw
 +		atprintbm("wagon step", t)
 +	end)
  end
  function advtrains.get_real_path_index(train, pit)
 @@ -492,88 +491,87 @@ function advtrains.get_real_path_index(train, pit)  end
  function wagon:on_rightclick(clicker)
 -return advtrains.pcall(function()
 -
 -	if not self:ensure_init() then return end
 -	if not clicker or not clicker:is_player() then
 -		return
 -	end
 -	if clicker:get_player_control().aux1 then
 -		--advtrains.dumppath(self:train().path)
 -		--minetest.chat_send_all("at index "..(self:train().index or "nil"))
 -		--advtrains.invert_train(self.train_id)
 -		atprint(dump(self))
 -		return
 -	end	
 -	local pname=clicker:get_player_name()
 -	local no=self:get_seatno(pname)
 -	if no then
 -		if self.seat_groups then
 -			local poss={}
 -			local sgr=self.seats[no].group
 -			for _,access in ipairs(self.seat_groups[sgr].access_to) do
 -				if self:check_seat_group_access(pname, access) then
 -					poss[#poss+1]={name=self.seat_groups[access].name, key="sgr_"..access}
 +	return advtrains.pcall(function()
 +		if not self:ensure_init() then return end
 +		if not clicker or not clicker:is_player() then
 +			return
 +		end
 +		if clicker:get_player_control().aux1 then
 +			--advtrains.dumppath(self:train().path)
 +			--minetest.chat_send_all("at index "..(self:train().index or "nil"))
 +			--advtrains.invert_train(self.train_id)
 +			atprint(dump(self))
 +			return
 +		end	
 +		local pname=clicker:get_player_name()
 +		local no=self:get_seatno(pname)
 +		if no then
 +			if self.seat_groups then
 +				local poss={}
 +				local sgr=self.seats[no].group
 +				for _,access in ipairs(self.seat_groups[sgr].access_to) do
 +					if self:check_seat_group_access(pname, access) then
 +						poss[#poss+1]={name=self.seat_groups[access].name, key="sgr_"..access}
 +					end
  				end
 -			end
 -			if self.has_inventory and self.get_inventory_formspec then
 -				poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
 -			end
 -			if self.owner==pname then
 -				poss[#poss+1]={name=attrans("Wagon properties"), key="prop"}
 -			end
 -			if not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0 then
 -				poss[#poss+1]={name=attrans("Get off"), key="off"}
 -			else
 -				if clicker:get_player_control().sneak then
 -					poss[#poss+1]={name=attrans("Get off (forced)"), key="off"}
 +				if self.has_inventory and self.get_inventory_formspec then
 +					poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
 +				end
 +				if self.owner==pname then
 +					poss[#poss+1]={name=attrans("Wagon properties"), key="prop"}
 +				end
 +				if not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0 then
 +					poss[#poss+1]={name=attrans("Get off"), key="off"}
  				else
 -					poss[#poss+1]={name=attrans("(Doors closed)"), key="dcwarn"}
 +					if clicker:get_player_control().sneak then
 +						poss[#poss+1]={name=attrans("Get off (forced)"), key="off"}
 +					else
 +						poss[#poss+1]={name=attrans("(Doors closed)"), key="dcwarn"}
 +					end
  				end
 -			end
 -			if #poss==0 then
 -				--can't do anything.
 -			elseif #poss==1 then
 -				self:seating_from_key_helper(pname, {[poss[1].key]=true}, no)
 -			else
 -				local form = "size[5,"..1+(#poss).."]"
 -				for pos,ent in ipairs(poss) do
 -					form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"
 +				if #poss==0 then
 +					--can't do anything.
 +				elseif #poss==1 then
 +					self:seating_from_key_helper(pname, {[poss[1].key]=true}, no)
 +				else
 +					local form = "size[5,"..1+(#poss).."]"
 +					for pos,ent in ipairs(poss) do
 +						form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"
 +					end
 +					minetest.show_formspec(pname, "advtrains_seating_"..self.unique_id, form)
  				end
 -				minetest.show_formspec(pname, "advtrains_seating_"..self.unique_id, form)
 +			else
 +				self:get_off(no)
  			end
  		else
 -			self:get_off(no)
 -		end
 -	else
 -		--do not attach if already on a train
 -		if advtrains.player_to_train_mapping[pname] then return end
 -		if self.seat_groups then
 -			if #self.seats==0 then
 -				if self.has_inventory and self.get_inventory_formspec then
 -					minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname))
 +			--do not attach if already on a train
 +			if advtrains.player_to_train_mapping[pname] then return end
 +			if self.seat_groups then
 +				if #self.seats==0 then
 +					if self.has_inventory and self.get_inventory_formspec then
 +						minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname))
 +					end
 +					return
  				end
 -				return
 -			end
 -			
 -			local doors_open = self:train().door_open~=0 or clicker:get_player_control().sneak
 -			for _,sgr in ipairs(self.assign_to_seat_group) do
 -				if self:check_seat_group_access(pname, sgr) then
 -					for seatid, seatdef in ipairs(self.seats) do
 -						if seatdef.group==sgr and not self.seatp[seatid] and (not self.seat_groups[sgr].require_doors_open or doors_open) then
 -							self:get_on(clicker, seatid)
 -							return
 +				
 +				local doors_open = self:train().door_open~=0 or clicker:get_player_control().sneak
 +				for _,sgr in ipairs(self.assign_to_seat_group) do
 +					if self:check_seat_group_access(pname, sgr) then
 +						for seatid, seatdef in ipairs(self.seats) do
 +							if seatdef.group==sgr and not self.seatp[seatid] and (not self.seat_groups[sgr].require_doors_open or doors_open) then
 +								self:get_on(clicker, seatid)
 +								return
 +							end
  						end
  					end
  				end
 +				minetest.chat_send_player(pname, attrans("Can't get on: wagon full or doors closed!"))
 +				minetest.chat_send_player(pname, attrans("Use Sneak+rightclick to bypass closed doors!"))
 +			else
 +				self:show_get_on_form(pname)
  			end
 -			minetest.chat_send_player(pname, attrans("Can't get on: wagon full or doors closed!"))
 -			minetest.chat_send_player(pname, attrans("Use Sneak+rightclick to bypass closed doors!"))
 -		else
 -			self:show_get_on_form(pname)
  		end
 -	end
 -end)
 +	end)
  end
  function wagon:get_on(clicker, seatno)
 @@ -718,80 +716,79 @@ function wagon:show_wagon_properties(pname)  	minetest.show_formspec(pname, "advtrains_prop_"..self.unique_id, form)
  end
  minetest.register_on_player_receive_fields(function(player, formname, fields)
 -return advtrains.pcall(function()
 -
 -	local uid=string.match(formname, "^advtrains_geton_(.+)$")
 -	if uid then
 -		for _,wagon in pairs(minetest.luaentities) do
 -			if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
 -				if fields.inv then
 -					if wagon.has_inventory and wagon.get_inventory_formspec then
 -						minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..uid, wagon:get_inventory_formspec(player:get_player_name()))
 -					end
 -				elseif fields.seat then
 -					local val=minetest.explode_textlist_event(fields.seat)
 -					if val and val.type~="INV" and not wagon.seatp[player:get_player_name()] then
 -					--get on
 -						wagon:get_on(player, val.index)
 -						--will work with the new close_formspec functionality. close exactly this formspec.
 -						minetest.show_formspec(player:get_player_name(), formname, "")
 +	return advtrains.pcall(function()
 +		local uid=string.match(formname, "^advtrains_geton_(.+)$")
 +		if uid then
 +			for _,wagon in pairs(minetest.luaentities) do
 +				if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
 +					if fields.inv then
 +						if wagon.has_inventory and wagon.get_inventory_formspec then
 +							minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..uid, wagon:get_inventory_formspec(player:get_player_name()))
 +						end
 +					elseif fields.seat then
 +						local val=minetest.explode_textlist_event(fields.seat)
 +						if val and val.type~="INV" and not wagon.seatp[player:get_player_name()] then
 +						--get on
 +							wagon:get_on(player, val.index)
 +							--will work with the new close_formspec functionality. close exactly this formspec.
 +							minetest.show_formspec(player:get_player_name(), formname, "")
 +						end
  					end
  				end
  			end
  		end
 -	end
 -	uid=string.match(formname, "^advtrains_seating_(.+)$")
 -	if uid then
 -		for _,wagon in pairs(minetest.luaentities) do
 -			if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
 -				local pname=player:get_player_name()
 -				local no=wagon:get_seatno(pname)
 -				if no then
 -					if wagon.seat_groups then
 -						wagon:seating_from_key_helper(pname, fields, no)
 +		uid=string.match(formname, "^advtrains_seating_(.+)$")
 +		if uid then
 +			for _,wagon in pairs(minetest.luaentities) do
 +				if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
 +					local pname=player:get_player_name()
 +					local no=wagon:get_seatno(pname)
 +					if no then
 +						if wagon.seat_groups then
 +							wagon:seating_from_key_helper(pname, fields, no)
 +						end
  					end
  				end
  			end
  		end
 -	end
 -	uid=string.match(formname, "^advtrains_prop_(.+)$")
 -	if uid then
 -		for _,wagon in pairs(minetest.luaentities) do
 -			if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
 -				local pname=player:get_player_name()
 -				if pname~=wagon.owner then
 -					return true
 -				end
 -				if fields.save or not fields.quit then
 -					for sgr,sgrdef in pairs(wagon.seat_groups) do
 -						if fields["sgr_"..sgr] then
 -							local fcont = fields["sgr_"..sgr]
 -							wagon.seat_access[sgr] = fcont~="" and fcont or nil
 -						end
 -					end
 -					if fields.lock_couples then
 -						wagon.lock_couples = fields.lock_couples == "true"
 +		uid=string.match(formname, "^advtrains_prop_(.+)$")
 +		if uid then
 +			for _,wagon in pairs(minetest.luaentities) do
 +				if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
 +					local pname=player:get_player_name()
 +					if pname~=wagon.owner then
 +						return true
  					end
 -					if fields.text_outside then
 -						if fields.text_outside~="" then
 -							wagon:train().text_outside=fields.text_outside
 -						else
 -							wagon:train().text_outside=nil
 +					if fields.save or not fields.quit then
 +						for sgr,sgrdef in pairs(wagon.seat_groups) do
 +							if fields["sgr_"..sgr] then
 +								local fcont = fields["sgr_"..sgr]
 +								wagon.seat_access[sgr] = fcont~="" and fcont or nil
 +							end
  						end
 -					end
 -					if fields.text_inside then
 -						if fields.text_inside~="" then
 -							wagon:train().text_inside=fields.text_inside
 -						else
 -							wagon:train().text_inside=nil
 +						if fields.lock_couples then
 +							wagon.lock_couples = fields.lock_couples == "true"
 +						end
 +						if fields.text_outside then
 +							if fields.text_outside~="" then
 +								wagon:train().text_outside=fields.text_outside
 +							else
 +								wagon:train().text_outside=nil
 +							end
  						end
 +						if fields.text_inside then
 +							if fields.text_inside~="" then
 +								wagon:train().text_inside=fields.text_inside
 +							else
 +								wagon:train().text_inside=nil
 +							end
 +						end
 +						
  					end
 -					
  				end
  			end
  		end
 -	end
 -end)
 +	end)
  end)
  function wagon:seating_from_key_helper(pname, fields, no)
  	local sgr=self.seats[no].group
 @@ -855,42 +852,42 @@ function advtrains.register_wagon(sysname, prototype, desc, inv_img)  		on_place = function(itemstack, placer, pointed_thing)
  			return advtrains.pcall(function()
 -			if not pointed_thing.type == "node" then
 -				return
 -			end
 -			
 +				if not pointed_thing.type == "node" then
 +					return
 +				end
 +				
 -			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, prototype.drives_on)) then
 -				atprint("no track here, not placing.")
 +				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, prototype.drives_on)) then
 +					atprint("no track here, not placing.")
 +					return itemstack
 +				end
 +				if not minetest.check_player_privs(placer, {train_place = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
 +					minetest.record_protection_violation(pointed_thing.under, placer:get_player_name())
 +					return
 +				end
 +				local conn1=advtrains.get_track_connections(node.name, node.param2)
 +				local id=advtrains.create_new_train_at(pointed_thing.under, advtrains.dirCoordSet(pointed_thing.under, conn1))
 +				
 +				local ob=minetest.add_entity(pointed_thing.under, "advtrains:"..sysname)
 +				if not ob then
 +					atprint("couldn't add_entity, aborting")
 +				end
 +				local le=ob:get_luaentity()
 +				
 +				le.owner=placer:get_player_name()
 +				
 +				local wagon_uid=le:init_new_instance(id, {})
 +				
 +				advtrains.add_wagon_to_train(le, id)
 +				if not minetest.setting_getbool("creative_mode") then
 +					itemstack:take_item()
 +				end
  				return itemstack
 -			end
 -			if not minetest.check_player_privs(placer, {train_place = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
 -				minetest.record_protection_violation(pointed_thing.under, placer:get_player_name())
 -				return
 -			end
 -			local conn1=advtrains.get_track_connections(node.name, node.param2)
 -			local id=advtrains.create_new_train_at(pointed_thing.under, advtrains.dirCoordSet(pointed_thing.under, conn1))
 -			
 -			local ob=minetest.add_entity(pointed_thing.under, "advtrains:"..sysname)
 -			if not ob then
 -				atprint("couldn't add_entity, aborting")
 -			end
 -			local le=ob:get_luaentity()
 -			
 -			le.owner=placer:get_player_name()
 -			
 -			local wagon_uid=le:init_new_instance(id, {})
 -			
 -			advtrains.add_wagon_to_train(le, id)
 -			if not minetest.setting_getbool("creative_mode") then
 -				itemstack:take_item()
 -			end
 -			return itemstack
 -			
 -		end)
 +				
 +			end)
  		end,
  	})
  end
 diff --git a/advtrains/advtrains_itrainmap/init.lua b/advtrains/advtrains_itrainmap/init.lua index 96e30c5..756f1da 100644 --- a/advtrains/advtrains_itrainmap/init.lua +++ b/advtrains/advtrains_itrainmap/init.lua @@ -128,7 +128,7 @@ minetest.register_chatcommand("itm_cache_ndb", {  })  local timer=0 -minetest.register_globalstep(function(dtime) +function advtrains_itm_mainloop(dtime)  	timer=timer-math.min(dtime, 0.1)  	if timer<=0 then  		for pname,d in pairs(itm_pdata) do @@ -136,12 +136,14 @@ minetest.register_globalstep(function(dtime)  		end  		timer=2  	end -end) +end  minetest.register_on_player_receive_fields(function(player, formname, fields)  	if formname=="itrainmap" and fields.quit then  		itm_pdata[player:get_player_name()]=nil  	end  end) ---automatically run itm_cache_ndb -minetest.after(2, cache_ndb) +function advtrains_itm_init() +	--automatically run itm_cache_ndb +	minetest.after(2, cache_ndb) +end diff --git a/advtrains/advtrains_luaautomation/init.lua b/advtrains/advtrains_luaautomation/init.lua index 71808e7..0257aef 100644 --- a/advtrains/advtrains_luaautomation/init.lua +++ b/advtrains/advtrains_luaautomation/init.lua @@ -40,29 +40,32 @@ dofile(mp.."/chatcmds.lua")  local filename=minetest.get_worldpath().."/advtrains_luaautomation" -local file, err = io.open(filename, "r") -if not file then -	minetest.log("error", " Failed to read advtrains_luaautomation save data from file "..filename..": "..(err or "Unknown Error")) -else -	atprint("luaautomation reading file:",filename) -	local tbl = minetest.deserialize(file:read("*a")) -	if type(tbl) == "table" then -		if tbl.version==1 then -			for envname, data in pairs(tbl.envs) do -				atlatc.envs[envname]=atlatc.env_load(envname, data) + +function atlatc.load() +	local file, err = io.open(filename, "r") +	if not file then +		minetest.log("error", " Failed to read advtrains_luaautomation save data from file "..filename..": "..(err or "Unknown Error")) +	else +		atprint("luaautomation reading file:",filename) +		local tbl = minetest.deserialize(file:read("*a")) +		if type(tbl) == "table" then +			if tbl.version==1 then +				for envname, data in pairs(tbl.envs) do +					atlatc.envs[envname]=atlatc.env_load(envname, data) +				end +				atlatc.active.load(tbl.active) +				atlatc.interrupt.load(tbl.interrupt) +				atlatc.pcnaming.load(tbl.pcnaming)  			end -			atlatc.active.load(tbl.active) -			atlatc.interrupt.load(tbl.interrupt) -			atlatc.pcnaming.load(tbl.pcnaming) +		else +			minetest.log("error", " Failed to read advtrains_luaautomation save data from file "..filename..": Not a table!")  		end -	else -		minetest.log("error", " Failed to read advtrains_luaautomation save data from file "..filename..": Not a table!") +		file:close()  	end -	file:close() +	-- run init code of all environments +	atlatc.run_initcode()  end --- run init code of all environments -atlatc.run_initcode()  atlatc.save = function()  	--versions: @@ -94,21 +97,14 @@ atlatc.save = function()  	file:close()  end -minetest.register_on_shutdown(atlatc.save)  -- globalstep for step code  local timer, step_int=0, 2 -local stimer, sstep_int=0, 10 -minetest.register_globalstep(function(dtime) +function atlatc.mainloop_stepcode(dtime)  	timer=timer+dtime  	if timer>step_int then  		timer=0  		atlatc.run_stepcode()  	end -	stimer=stimer+dtime -	if stimer>sstep_int then -		stimer=0 -		atlatc.save() -	end -end) +end diff --git a/advtrains/advtrains_luaautomation/interrupt.lua b/advtrains/advtrains_luaautomation/interrupt.lua index b8fc879..718b8c7 100644 --- a/advtrains/advtrains_luaautomation/interrupt.lua +++ b/advtrains/advtrains_luaautomation/interrupt.lua @@ -21,30 +21,25 @@ function iq.add(t, pos, evtdata)  	run=true  end -minetest.register_globalstep(function(dtime) -return advtrains.pcall(function() - -	if run then -		timer=timer + math.min(dtime, 0.2) -		for i=1,#queue do -			local qe=queue[i] -			if not qe then -				table.remove(queue, i) -				i=i-1 -			elseif timer>qe.t then -				local pos, evtdata=queue[i].p, queue[i].e -				local node=advtrains.ndb.get_node(pos) -				local ndef=minetest.registered_nodes[node.name] -				if ndef and ndef.luaautomation and ndef.luaautomation.fire_event then -					ndef.luaautomation.fire_event(pos, evtdata) -				end -				table.remove(queue, i) -				i=i-1 +function iq.mainloop(dtime) +	timer=timer + math.min(dtime, 0.2) +	for i=1,#queue do +		local qe=queue[i] +		if not qe then +			table.remove(queue, i) +			i=i-1 +		elseif timer>qe.t then +			local pos, evtdata=queue[i].p, queue[i].e +			local node=advtrains.ndb.get_node(pos) +			local ndef=minetest.registered_nodes[node.name] +			if ndef and ndef.luaautomation and ndef.luaautomation.fire_event then +				ndef.luaautomation.fire_event(pos, evtdata)  			end +			table.remove(queue, i) +			i=i-1  		end  	end -end) -end) +end | 
