From 054a7b188e78d1afd1de218ad6f5433f7c5d58e2 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Mon, 30 May 2016 19:59:13 +0200 Subject: removed debug messages --- trainlogic.lua | 10 +- trainlogic.lua~ | 626 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 631 insertions(+), 5 deletions(-) create mode 100644 trainlogic.lua~ diff --git a/trainlogic.lua b/trainlogic.lua index d12dfa2..6bd8310 100644 --- a/trainlogic.lua +++ b/trainlogic.lua @@ -186,14 +186,14 @@ function advtrains.train_step(id, train, dtime) 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 and posfront and posback then - print(minetest.pos_to_string(posfront)) + --print(minetest.pos_to_string(posfront)) local should_check=false for _,p in ipairs(minetest.get_connected_players()) do should_check=should_check or ((vector.distance(posfront, p:getpos())train.max_index_on_track + local back_off_track=train.min_index_on_track and (train.index-train.trainlen)1 then train.tarvelocity=1 end + if train.tarvelocity<-1 then train.tarvelocity=-1 end + elseif front_off_track then--allow movement only backward + if train.tarvelocity>0 then train.tarvelocity=0 end + if train.tarvelocity<-1 then train.tarvelocity=-1 end + elseif back_off_track then--allow movement only forward + if train.tarvelocity>1 then train.tarvelocity=1 end + if train.tarvelocity<0 then train.tarvelocity=0 end + end + + --move + if not train.velocity then + train.velocity=0 + end + train.index=train.index and train.index+((train.velocity/(train.path_dist[math.floor(train.index)] or 1))*dtime) or 0 + --check for collisions by finding objects + --front + local search_radius=4 + + local posfront=path[math.floor(train.index+1)] + if posfront then + local objrefs=minetest.get_objects_inside_radius(posfront, 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 + local posback=path[math.floor(train.index-(train.trainlen or 0)-1)] + if posback then + local objrefs=minetest.get_objects_inside_radius(posback, 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 + + --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 + 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 and posfront and posback then + print(minetest.pos_to_string(posfront)) + local should_check=false + for _,p in ipairs(minetest.get_connected_players()) do + should_check=should_check or ((vector.distance(posfront, p:getpos())0 then--accelerating, force will be brought on only by locomotives. + --print("accelerating with default force") + applydiff=(math.min((advtrains.train_accel_force*train.locomotives_in_train*dtime)/mass, math.abs(diff))) + else--decelerating + if front_off_track or back_off_track or train.recently_collided_with_env then --every wagon has a brake, so not divided by mass. + --print("braking with emergency force") + applydiff=(math.min((advtrains.train_emerg_force*dtime), math.abs(diff))) + else + --print("braking with default force") + applydiff=(math.min((advtrains.train_brake_force*dtime), math.abs(diff))) + end + end + train.velocity=train.velocity+(applydiff*math.sign(train.tarvelocity-train.velocity)) + end + +end + +--the 'leader' concept has been overthrown, we won't rely on MT's "buggy object management" +--structure of train table: +--[[ +trains={ + [train_id]={ + trainparts={ + [n]=wagon_id + } + path={path} + velocity + tarvelocity + index + trainlen + path_inv_level + last_pos | + last_dir | for pathpredicting. + no_connect_for_movements (index way counter for when not to connect again) TODO implement + } +} +--a wagon itself has the following properties: +wagon={ + unique_id + train_id + pos_in_train (is index difference, including train_span stuff) + pos_in_trainparts (is index in trainparts tabel of trains) +} +inherited by metatable: +wagon_proto={ + wagon_span +} +]] + +--returns new id +function advtrains.create_new_train_at(pos, pos_prev, traintype) + local newtrain_id=os.time()..os.clock() + while advtrains.trains[newtrain_id] do newtrain_id=os.time()..os.clock() end--ensure uniqueness(will be unneccessary) + + advtrains.trains[newtrain_id]={} + advtrains.trains[newtrain_id].last_pos=pos + advtrains.trains[newtrain_id].last_pos_prev=pos_prev + advtrains.trains[newtrain_id].traintype=traintype + advtrains.trains[newtrain_id].tarvelocity=0 + advtrains.trains[newtrain_id].velocity=0 + advtrains.trains[newtrain_id].trainparts={} + return newtrain_id +end + +--returns false on failure. handle this case! +function advtrains.pathpredict(id, train) + + --print("pos ",x,y,z) + --::rerun:: + if not train.index then train.index=0 end + if not train.path or #train.path<2 then + if not train.last_pos then + --no chance to recover + print("[advtrains]train hasn't saved last-pos, removing train.") + advtrains.train[id]=nil + return false + end + + local node_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(train.last_pos), train.traintype) + + if node_ok==nil then + --block not loaded, do nothing + return nil + elseif node_ok==false then + print("[advtrains]no track here, (fail) removing train.") + advtrains.trains[id]=nil + return false + end + + if not train.last_pos_prev then + --no chance to recover + print("[advtrains]train hasn't saved last-pos_prev, removing train.") + advtrains.trains[id]=nil + return false + end + + local prevnode_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(train.last_pos_prev), train.traintype) + + if prevnode_ok==nil then + --block not loaded, do nothing + return nil + elseif prevnode_ok==false then + print("[advtrains]no track at prev, (fail) removing train.") + advtrains.trains[id]=nil + return false + end + + train.index=(train.restore_add_index or 0)+(train.savedpos_off_track_index_offset or 0) + --restore_add_index is set by save() to prevent trains hopping to next round index. should be between -0.5 and 0.5 + --savedpos_off_track_index_offset is set if train went off track. see below. + train.path={} + train.path_dist={} + train.path[0]=train.last_pos + train.path[-1]=train.last_pos_prev + train.path_dist[-1]=vector.distance(train.last_pos, train.last_pos_prev) + end + + local maxn=advtrains.maxN(train.path) + while (maxn-train.index) < 2 do--pregenerate + --print("[advtrains]maxn conway for ",maxn,minetest.pos_to_string(path[maxn]),maxn-1,minetest.pos_to_string(path[maxn-1])) + local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.traintype) + if conway then + train.path[maxn+1]=conway + train.max_index_on_track=maxn + else + --do as if nothing has happened and preceed with path + --but do not update max_index_on_track + print("over-generating path max to index "..maxn+1) + 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=advtrains.maxN(train.path) + end + + local minn=advtrains.minN(train.path) + while (train.index-minn) < (train.trainlen or 0) + 2 do --post_generate. has to be at least trainlen. + --print("[advtrains]minn conway for ",minn,minetest.pos_to_string(path[minn]),minn+1,minetest.pos_to_string(path[minn+1])) + local conway=advtrains.conway(train.path[minn], train.path[minn+1], train.traintype) + if conway then + train.path[minn-1]=conway + train.min_index_on_track=minn + else + --do as if nothing has happened and preceed with path + --but do not update min_index_on_track + print("over-generating path min to index "..minn-1) + 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=advtrains.minN(train.path) + end + if not train.min_index_on_track then train.min_index_on_track=0 end + if not train.max_index_on_track then train.max_index_on_track=0 end + + --make pos/yaw available for possible recover calls + if train.max_index_on_tracktrain.index then --whoops, train went even more far. same behavior + train.savedpos_off_track_index_offset=train.index-train.min_index_on_track + train.last_pos=train.path[train.min_index_on_track+1] + train.last_pos_prev=train.path[train.min_index_on_track] + --print("train is off-track (back), last positions kept at "..minetest.pos_to_string(train.last_pos).." / "..minetest.pos_to_string(train.last_pos_prev)) + else --regular case + train.savedpos_off_track_index_offset=nil + train.last_pos=train.path[math.floor(train.index+0.5)] + train.last_pos_prev=train.path[math.floor(train.index-0.5)] + end + return train.path +end + +function advtrains.get_or_create_path(id, train) + if not train.path then return advtrains.pathpredict(id, train) end + + return train.path +end + +function advtrains.add_wagon_to_train(wagon, train_id, index) + local train=advtrains.trains[train_id] + if index then + table.insert(train.trainparts, index, wagon.unique_id) + else + table.insert(train.trainparts, wagon.unique_id) + end + --this is not the usual case!!! + --we may set initialized because the wagon has no chance to step() + wagon.initialized=true + advtrains.update_trainpart_properties(train_id) +end +function advtrains.update_trainpart_properties(train_id, invert_flipstate) + local train=advtrains.trains[train_id] + local rel_pos=0 + local count_l=0 + for i, w_id in ipairs(train.trainparts) do + local any_loaded=false + for _,wagon in pairs(minetest.luaentities) do + if wagon.is_wagon and wagon.initialized and wagon.unique_id==w_id then + rel_pos=rel_pos+wagon.wagon_span + wagon.train_id=train_id + wagon.pos_in_train=rel_pos + wagon.pos_in_trainparts=i + wagon.old_velocity_vector=nil + if wagon.is_locomotive then + count_l=count_l+1 + end + if invert_flipstate then + wagon.wagon_flipped = not wagon.wagon_flipped + end + rel_pos=rel_pos+wagon.wagon_span + any_loaded=true + end + end + if not any_loaded then + print("update_trainpart_properties wagon "..w_id.." not loaded, ignoring it.") + end + end + train.trainlen=rel_pos + train.locomotives_in_train=count_l +end + +function advtrains.split_train_at_wagon(wagon) + --get train + local train=advtrains.trains[wagon.train_id] + local pos_for_new_train=advtrains.get_or_create_path(wagon.train_id, train)[math.floor((train.index or 0)-wagon.pos_in_train-0.5)] + local pos_for_new_train_prev=advtrains.get_or_create_path(wagon.train_id, train)[math.floor((train.index or 0)-wagon.pos_in_train-1.5)] + + --before doing anything, check if both are rails. else do not allow + if not pos_for_new_train then + print("split_train: pos_for_new_train not set") + return false + end + local node_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(pos_for_new_train), train.traintype) + if not node_ok then + print("split_train: pos_for_new_train "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." not loaded or is not a rail") + return false + end + + if not train.last_pos_prev then + print("split_train: pos_for_new_train_prev not set") + return false + end + + local prevnode_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(pos_for_new_train), train.traintype) + if not prevnode_ok then + print("split_train: pos_for_new_train_prev "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." not loaded or is not a rail") + return false + end + + --create subtrain + local newtrain_id=advtrains.create_new_train_at(pos_for_new_train, pos_for_new_train_prev, train.traintype) + local newtrain=advtrains.trains[newtrain_id] + --insert all wagons to new train + for k,v in ipairs(train.trainparts) do + if k>=wagon.pos_in_trainparts then + table.insert(newtrain.trainparts, v) + train.trainparts[k]=nil + end + end + --update train parts + advtrains.update_trainpart_properties(wagon.train_id)--atm it still is the desierd id. + advtrains.update_trainpart_properties(newtrain_id) + train.tarvelocity=0 + newtrain.velocity=train.velocity + newtrain.tarvelocity=0 +end + +--there are 4 cases: +--1/2. F<->R F<->R regular, put second train behind first +--->frontpos of first train will match backpos of second +--3. F<->R R<->F flip one of these trains, take the other as new train +--->backpos's will match +--4. R<->F F<->R flip one of these trains and take it as new parent +--->frontpos's will match +function advtrains.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.traintype~=train2.traintype then + --TODO implement collision without connection + return + end + if #train1.trainparts==0 or #train2.trainparts==0 then return end + + local frontpos1=train1.path[math.floor(train1.index+0.5)] + local backpos1=train1.path[math.floor(train1.index-(train1.trainlen or 2)+0.5)] + local frontpos2=train2.path[math.floor(train2.index+0.5)] + local backpos2=train2.path[math.floor(train2.index-(train1.trainlen or 2)+0.5)] + + if not frontpos1 or not frontpos2 or not backpos1 or not backpos2 then return end + + --case 1 (first train is front) + if vector.equals(frontpos2, backpos1) then + advtrains.do_connect_trains(id1, id2) + --case 2 (second train is front) + elseif vector.equals(frontpos1, backpos2) then + advtrains.do_connect_trains(id2, id1) + --case 3 + elseif vector.equals(backpos2, backpos1) then + advtrains.invert_train(id2) + advtrains.do_connect_trains(id1, id2) + --case 4 + elseif vector.equals(frontpos2, frontpos1) then + advtrains.invert_train(id1) + advtrains.do_connect_trains(id1, id2) + end +end +function advtrains.do_connect_trains(first_id, second_id) + local first_wagoncnt=#advtrains.trains[first_id].trainparts + local second_wagoncnt=#advtrains.trains[second_id].trainparts + + for _,v in ipairs(advtrains.trains[second_id].trainparts) do + table.insert(advtrains.trains[first_id].trainparts, v) + end + --kick it like physics (with mass being #wagons) + local new_velocity=((advtrains.trains[first_id].velocity*first_wagoncnt)+(advtrains.trains[second_id].velocity*second_wagoncnt))/(first_wagoncnt+second_wagoncnt) + advtrains.trains[second_id]=nil + advtrains.update_trainpart_properties(first_id) + advtrains.trains[first_id].velocity=new_velocity + advtrains.trains[first_id].tarvelocity=0 +end + +function advtrains.invert_train(train_id) + local train=advtrains.trains[train_id] + + local old_path=advtrains.get_or_create_path(train_id, train) + train.path={} + train.index=-train.index+train.trainlen + train.velocity=-train.velocity + train.tarvelocity=-train.tarvelocity + for k,v in pairs(old_path) do + train.path[-k]=v + end + local old_trainparts=train.trainparts + train.trainparts={} + for k,v in ipairs(old_trainparts) do + table.insert(train.trainparts, 1, v)--notice insertion at first place + end + advtrains.update_trainpart_properties(train_id, true) +end + +function advtrains.is_train_at_pos(pos) + --print("istrainat: pos "..minetest.pos_to_string(pos)) + local checked_trains={} + local objrefs=minetest.get_objects_inside_radius(pos, 2) + for _,v in pairs(objrefs) do + local le=v:get_luaentity() + if le and le.is_wagon and le.initialized and le.train_id and not checked_trains[le.train_id] then + --print("istrainat: checking "..le.train_id) + checked_trains[le.train_id]=true + local path=advtrains.get_or_create_path(le.train_id, le:train()) + if path then + --print("has path") + for i=math.floor(le:train().index-le:train().trainlen+0.5),math.floor(le:train().index+0.5) do + if path[i] then + --print("has pathitem "..i.." "..minetest.pos_to_string(path[i])) + if vector.equals(advtrains.round_vector_floor_y(path[i]), pos) then + return true + end + end + end + end + end + end + return false +end +function advtrains.invalidate_all_paths() + --print("invalidating all paths") + for k,v in pairs(advtrains.trains) do + if v.index then + v.restore_add_index=v.index-math.floor(v.index+0.5) + end + v.path=nil + v.index=nil + v.min_index_on_track=nil + v.max_index_on_track=nil + end +end \ No newline at end of file -- cgit v1.2.3