From 987cd5b7f0ef86884858a107cc915f548675f2a8 Mon Sep 17 00:00:00 2001
From: orwell96 <orwell@bleipb.de>
Date: Sat, 31 Dec 2016 15:16:19 +0100
Subject: spawn couple on train collision also fix empty trains hanging around
 for too long

---
 advtrains/couple.lua     |   2 +-
 advtrains/pseudoload.lua |   2 +-
 advtrains/trainlogic.lua | 190 ++++++++++++++++++++---------------------------
 3 files changed, 83 insertions(+), 111 deletions(-)

(limited to 'advtrains')

diff --git a/advtrains/couple.lua b/advtrains/couple.lua
index a846c8b..675bed5 100644
--- a/advtrains/couple.lua
+++ b/advtrains/couple.lua
@@ -140,7 +140,7 @@ minetest.register_entity("advtrains:couple", {
 		else
 			tp2=advtrains.get_real_index_position(train2.path, advtrains.get_train_end_index(train2))
 		end
-		if not tp1 or not tp2 or not (vector.distance(tp1,tp2)<0.5) then
+		if not tp1 or not tp2 or not (vector.distance(tp1,tp2)<1.5) then
 			self.object:remove()
 			return
 		else
diff --git a/advtrains/pseudoload.lua b/advtrains/pseudoload.lua
index 3f4f321..677cd14 100644
--- a/advtrains/pseudoload.lua
+++ b/advtrains/pseudoload.lua
@@ -176,7 +176,7 @@ function advtrains.reset_trackdb_position(pos)
 	if not advtrains.trackdb[rdp.y] then advtrains.trackdb[rdp.y]={} end
 	if not advtrains.trackdb[rdp.y][rdp.x] then advtrains.trackdb[rdp.y][rdp.x]={} end
 	advtrains.trackdb[rdp.y][rdp.x][rdp.z]=nil
-	advtrains.get_rail_info_at(pos)--to restore it.
+	advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)--to restore it.
 end
 	
 
diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua
index bb38fce..1050d62 100644
--- a/advtrains/trainlogic.lua
+++ b/advtrains/trainlogic.lua
@@ -2,6 +2,7 @@
 --controls train entities stuff about connecting/disconnecting/colliding trains and other things
 
 local print=function(t, ...) minetest.log("action", table.concat({t, ...}, " ")) minetest.chat_send_all(table.concat({t, ...}, " ")) end
+local sid=function(id) return string.sub(id, -4) end
 --local print=function() end
 
 local benchmark=false
@@ -130,15 +131,7 @@ minetest.register_globalstep(function(dtime)
 	advtrains.save_and_audit_timer=advtrains.save_and_audit_timer-dtime
 	if advtrains.save_and_audit_timer<=0 then
 		local t=os.clock()
-		--print("[advtrains] audit step")
-		--clean up orphaned trains
-		for k,v in pairs(advtrains.trains) do
-			--advtrains.update_trainpart_properties(k)
-			if #v.trainparts==0 then
-				print("[advtrains][train "..k.."] has empty trainparts, removing.")
-				advtrains.trains[k]=nil
-			end
-		end
+		
 		--save
 		advtrains.save()
 		advtrains.save_and_audit_timer=advtrains.audit_interval
@@ -244,26 +237,17 @@ function advtrains.train_step(id, train, dtime)
 	train.detector_old_index = math.floor(train.index)
 	train.detector_old_end_index = math.floor(train_end_index)
 	
+	--remove?
+	if #train.trainparts==0 then
+		print("[advtrains][train "..sid(id).."] has empty trainparts, removing.")
+		advtrains.detector.leave_node(path[train.detector_old_index], id)
+		advtrains.trains[id]=nil
+		return
+	end
+	
 	if train_moves then
 		--check for collisions by finding objects
-		--front
-		local search_radius=4
 		
-		--coupling
-		local couple_outward=1
-		local posfront=advtrains.get_real_index_position(path, train.index+couple_outward)
-		local posback=advtrains.get_real_index_position(path, train_end_index-couple_outward)
-		for _,pos in ipairs({posfront, posback}) do
-			if pos then
-				local objrefs=minetest.get_objects_inside_radius(pos, search_radius)
-				for _,v in pairs(objrefs) do
-					local le=v:get_luaentity()
-					if le and le.is_wagon and le.initialized and le.train_id~=id then
-						advtrains.try_connect_trains(id, le.train_id)
-					end
-				end
-			end
-		end
 		--heh, new collision again.
 		--this time, based on NODES and the advtrains.detector.on_node table.
 		local collpos
@@ -277,24 +261,29 @@ function advtrains.train_step(id, train, dtime)
 			local rcollpos=advtrains.round_vector_floor_y(collpos)
 			for x=-1,1 do
 				for z=-1,1 do
-					local testpts=minetest.pos_to_string(vector.add(rcollpos, {x=x, y=0, z=z}))
+					local testpos=vector.add(rcollpos, {x=x, y=0, z=z})
+					local testpts=minetest.pos_to_string(testpos)
 					if advtrains.detector.on_node[testpts] and advtrains.detector.on_node[testpts]~=id then
 						--collides
+						advtrains.spawn_couple_on_collide(id, testpos, advtrains.detector.on_node[testpts], train.movedir==-1)
+						
 						train.recently_collided_with_env=true
 						train.velocity=0.5*train.velocity
 						train.movedir=train.movedir*-1
 						train.tarvelocity=0
+						
 					end
 				end
 			end
 		end
 	end
 	--check for any trainpart entities if they have been unloaded. do this only if train is near a player, to not spawn entities into unloaded areas
+	--todo function will be taken by update_trainpart_properties
 	train.check_trainpartload=(train.check_trainpartload or 0)-dtime
 	local node_range=(math.max((minetest.setting_get("active_block_range") or 0),1)*16)
 	if train.check_trainpartload<=0 then
 		local ori_pos=advtrains.get_real_index_position(path, train.index) --not much to calculate
-		print("[advtrains][train "..id.."] at "..minetest.pos_to_string(vector.round(ori_pos)))
+		--print("[advtrains][train "..id.."] at "..minetest.pos_to_string(vector.round(ori_pos)))
 		
 		local should_check=false
 		for _,p in ipairs(minetest.get_connected_players()) do
@@ -664,38 +653,7 @@ end
 --->backpos's will match
 --4.   R<->F F<->R flip one of these trains and take it as new parent
 --->frontpos's will match
-function advtrains.try_connect_trains(id1, id2)
-	local train1=advtrains.trains[id1]
-	local train2=advtrains.trains[id2]
-	if not train1 or not train2 then return end
-	if not train1.path or not train2.path then return end
-	if #train1.trainparts==0 or #train2.trainparts==0 then return end
-	
-	local frontpos1=advtrains.get_real_index_position(train1.path, train1.index)
-	local backpos1=advtrains.get_real_index_position(train1.path, advtrains.get_train_end_index(train1))
-	--couple logic
-	--if train1.traintype==train2.traintype then
-		local frontpos2=advtrains.get_real_index_position(train2.path, train2.index)
-		local backpos2=advtrains.get_real_index_position(train2.path, advtrains.get_train_end_index(train2))
-		
-		if not frontpos1 or not frontpos2 or not backpos1 or not backpos2 then return end
-		
-		local couple_spawnradius=0.7
-		--case 1 (first train is front)
-		if vector.distance(frontpos2, backpos1)<couple_spawnradius then
-			advtrains.spawn_couple_if_neccessary(backpos1, frontpos2, id1, id2, true, false)
-			--case 2 (second train is front)
-		elseif vector.distance(frontpos1, backpos2)<couple_spawnradius then
-			advtrains.spawn_couple_if_neccessary(backpos2, frontpos1, id2, id1, true, false)
-			--case 3 
-		elseif vector.distance(backpos2, backpos1)<couple_spawnradius then
-			advtrains.spawn_couple_if_neccessary(backpos1, backpos2, id1, id2, true, true)
-			--case 4 
-		elseif vector.distance(frontpos2, frontpos1)<couple_spawnradius then
-			advtrains.spawn_couple_if_neccessary(frontpos1, frontpos2, id1, id2, false, false)
-		end
-	--end
-end
+
 --true when trains are facing each other. needed on colliding.
 -- check done by iterating paths and checking their direction
 --returns nil when not on the same track at all OR when required path items are not generated. this distinction may not always be needed.
@@ -713,72 +671,86 @@ function advtrains.trains_facing(train1, train2)
 	return nil
 end
 
---order of trains may be irrelevant in some cases. check opposite cases. TODO does this work?
---pos1 and pos2 are just needed to form a median.
-function advtrains.spawn_couple_if_neccessary(pos1, pos2, tid1, tid2, train1_is_backpos, train2_is_backpos)
-	--print("spawn_couple_if_neccessary..."..dump({pos1=pos1, pos2=pos2, train1_is_backpos=train1_is_backpos, train2_is_backpos=train2_is_backpos}))
-	local train1=advtrains.trains[tid1]
-	local train2=advtrains.trains[tid2]
+function advtrains.spawn_couple_on_collide(id1, pos, id2, t1_is_backpos)
+	print("COLLISION: "..sid(id1).." and "..sid(id2).." at "..minetest.pos_to_string(pos)..", t1_is_backpos="..(t1_is_backpos and "true" or "false"))
+	--TODO:
+	local train1=advtrains.trains[id1]
+	local train2=advtrains.trains[id2]
+	
+	local found
+	for i=advtrains.minN(train1.path), advtrains.maxN(train1.path) do
+		if vector.equals(train1.path[i], pos) then
+			found=true
+		end
+	end
+	if not found then
+		print("Err: pos not in path")
+		return 
+	end
+	
+	local frontpos2=train2.path[math.floor(train2.detector_old_index)]
+	local backpos2=train2.path[math.floor(train2.detector_old_end_index)]
+	local t2_is_backpos
+	print("End positions: "..minetest.pos_to_string(frontpos2)..minetest.pos_to_string(backpos2))
+	
+	if vector.equals(frontpos2, pos) then
+		t2_is_backpos=false
+	elseif vector.equals(backpos2, pos) then
+		t2_is_backpos=true
+	else
+		print("Err: not a endpos")
+		return --the collision position is not the end position.
+	end
+	print("t2_is_backpos="..(t2_is_backpos and "true" or "false"))
+	
 	local t1_has_couple
-	if train1_is_backpos then
+	if t1_is_backpos then
 		t1_has_couple=train1.couple_eid_back
 	else
 		t1_has_couple=train1.couple_eid_front
 	end
 	local t2_has_couple
-	if train2_is_backpos then
+	if t2_is_backpos then
 		t2_has_couple=train2.couple_eid_back
 	else
 		t2_has_couple=train2.couple_eid_front
 	end
 	
-	if t1_has_couple and t2_has_couple then
-		if t1_has_couple~=t2_has_couple then--what the hell
-			if minetest.object_refs[t2_has_couple] then minetest.object_refs[t2_has_couple]:remove() end
-			if train2_is_backpos then
-				train2.couple_eid_back=t1_has_couple
+	if t1_has_couple then
+		if minetest.object_refs[t1_has_couple] then minetest.object_refs[t1_has_couple]:remove() end
+	end
+	if t2_has_couple then
+		if minetest.object_refs[t2_has_couple] then minetest.object_refs[t2_has_couple]:remove() end
+	end
+	local obj=minetest.add_entity(pos, "advtrains:couple")
+	if not obj then print("failed creating object") return end
+	local le=obj:get_luaentity()
+	le.train_id_1=id1
+	le.train_id_2=id2
+	le.train1_is_backpos=t1_is_backpos
+	le.train2_is_backpos=t2_is_backpos
+	--find in object_refs
+	for aoi, compare in pairs(minetest.object_refs) do
+		if compare==obj then
+			if t1_is_backpos then
+				train1.couple_eid_back=aoi
 			else
-				train2.couple_eid_front=t1_has_couple
+				train1.couple_eid_front=aoi
 			end
-		end
-	--[[elseif t1_has_couple and not t2_has_couple then
-		if train2_is_backpos then
-			train2.couple_eid_back=t1_has_couple
-		else
-			train2.couple_eid_front=t1_has_couple
-		end
-	elseif not t1_has_couple and t2_has_couple then
-		if train1_is_backpos then
-			train1.couple_eid_back=t2_has_couple
-		else
-			train1.couple_eid_front=t2_has_couple
-		end]]
-	else
-		local pos=advtrains.pos_median(pos1, pos2)
-		local obj=minetest.add_entity(pos, "advtrains:couple")
-		if not obj then print("failed creating object") return end
-		local le=obj:get_luaentity()
-		le.train_id_1=tid1
-		le.train_id_2=tid2
-		le.train1_is_backpos=train1_is_backpos
-		le.train2_is_backpos=train2_is_backpos
-		--find in object_refs
-		for aoi, compare in pairs(minetest.object_refs) do
-			if compare==obj then
-				if train1_is_backpos then
-					train1.couple_eid_back=aoi
-				else
-					train1.couple_eid_front=aoi
-				end
-				if train2_is_backpos then
-					train2.couple_eid_back=aoi
-				else
-					train2.couple_eid_front=aoi
-				end
+			if t2_is_backpos then
+				train2.couple_eid_back=aoi
+			else
+				train2.couple_eid_front=aoi
 			end
 		end
 	end
+	print("Couple entity:"..dump(le))
+	
+	--also TODO: integrate check_trainpartload into update_trainpart_properties. 
 end
+--order of trains may be irrelevant in some cases. check opposite cases. TODO does this work?
+--pos1 and pos2 are just needed to form a median.
+
 
 function advtrains.do_connect_trains(first_id, second_id)
 	local first_wagoncnt=#advtrains.trains[first_id].trainparts
-- 
cgit v1.2.3