Gabriel Pérez-Cerezo 2019-12-01 12:09:04 +01:00
commit 0518fbbf3a
5 changed files with 55 additions and 125 deletions

View File

@ -85,9 +85,9 @@ end
--[[
Distance needed to accelerate from v0 to v1 with constant acceleration a:
v1 - v0 a / v1 - v0 \ 2
s = v0 * ------- + - * | ------- |
a 2 \ a /
v1 - v0 a / v1 - v0 \ 2 v1^2 - v0^2
s = v0 * ------- + - * | ------- | = -----------
a 2 \ a / 2*a
]]
local function apply_control(id, train)
@ -112,8 +112,7 @@ local function apply_control(id, train)
local v0 = train.velocity
local v1 = it.spd
if v1 and v1 <= v0 then
local f = (v1-v0) / a
local s = v0*f + a*f*f/2
local s = (v1*v1 - v0*v0) / (2*a)
local st = s + params.ADD_SLOW
if v0 > 3 then

View File

@ -1,48 +1,7 @@
-- occupation.lua
--[[
Collects and manages positions where trains occupy and/or reserve/require space
THIS SECTION ABOVE IS OUTDATED, look below
Zone diagram of a train:
|___| |___| --> Direction of travel
oo oo+oo oo
=|=======|===|===========|===|=======|===================|========|===
|SafetyB|CpB| Train |CpF|SafetyF| Brake |Aware |
[1] [2] [3] [4] [5] [6] [7] [8]
ID|Name |Desc
0 Free Zone that was occupied before, which has now been left
1 Train Zone where the train actually is.
2 SafetyB Safety zone behind the train. extends 4m
3 SafetyF Safety zone in front of the train. extends 4m
If a train is about to enter this zone, immediately brake it down to 2
4 CpB Backside coupling zone. If the coupling zones of 2 trains overlap, they can be coupled
5 CpF Frontside coupling zone
6 Brake Brake distance of the train. Extends to the point ~5 nodes in front
of the point where the train would stop if it would regularily brake now.
7 Aware Awareness zone. Extends 10-20 nodes beyond the Brake zone
Whenever any of the non-aware zones of other trains are detected here, the train will start to brake.
Table format:
occ[y][x][z] = {
[1] = train 1 id
[2] = train 1 ZoneID
// [3] = entry seqnum*
...
[2n-1] = train n id
[2n ] = train n ZoneID
// [3n-2] = train n id
// [3n-1] = train n ZoneID
// [3n ] = entry seqnum*
}
occ_chg[n] = {
pos = vector,
train_id,
old_val, (0 when entry did not exist before)
new_val, (0 when entry was deleted)
}
---------------------
It turned out that, especially for the TSS, some more, even overlapping zones are required.
Packing those into a data structure would just become a huge mess!
Instead, this occupation system will store the path indices of positions in the corresponding.

View File

@ -703,40 +703,6 @@ advtrains.te_register_on_remove(function(id, train)
--atdebug(id,"tnc remove",train.index,train.end_index)
end)
-- Calculates the indices where the window borders of the occupation windows are.
-- TODO adapt this code to new system, probably into a callback (probably only the brake distance code is needed)
local function calc_occwindows(id, train)
local end_index = advtrains.path_get_index_by_offset(train, train.index, -train.trainlen)
train.end_index = end_index
local cpl_b = end_index - COUPLE_ZONE
local safety_b = advtrains.path_get_index_by_offset(train, cpl_b, -SAFETY_ZONE)
local cpl_f = end_index + COUPLE_ZONE
local safety_f = advtrains.path_get_index_by_offset(train, cpl_f, SAFETY_ZONE)
-- calculate brake distance
local acc_all = t_accel_all[1]
local acc_eng = t_accel_eng[1]
local nwagons = #train.trainparts
local acc = acc_all + (acc_eng*train.locomotives_in_train)/nwagons
local vel = train.velocity
local brakedst = (vel*vel) / (2*acc)
local brake_i = math.max(advtrains.path_get_index_by_offset(train, train.index, brakedst + BRAKE_SPACE), safety_f)
local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE)
return {
safety_b,
cpl_b,
end_index,
train.index,
cpl_f,
safety_f,
brake_i,
aware_i,
}
end
--returns new id
function advtrains.create_new_train_at(pos, connid, ioff, trainparts)
local new_id=advtrains.random_id()
@ -985,21 +951,23 @@ function advtrains.train_check_couples(train)
if not train.cpl_front then
-- recheck front couple
local front_trains, pos = advtrains.occ.get_occupations(train, atround(train.index) + CPL_CHK_DST)
for tid, idx in pairs(front_trains) do
local other_train = advtrains.trains[tid]
if not advtrains.train_ensure_init(tid, other_train) then
atwarn("Train",tid,"is not initialized! Couldn't check couples!")
return
end
--atdebug(train.id,"front: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
if other_train.velocity == 0 then
if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
createcouple(pos, train, true, other_train, true)
break
if minetest.get_node_or_nil(pos) then -- if the position is loaded...
for tid, idx in pairs(front_trains) do
local other_train = advtrains.trains[tid]
if not advtrains.train_ensure_init(tid, other_train) then
atwarn("Train",tid,"is not initialized! Couldn't check couples!")
return
end
if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
createcouple(pos, train, true, other_train, false)
break
--atdebug(train.id,"front: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
if other_train.velocity == 0 then
if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
createcouple(pos, train, true, other_train, true)
break
end
if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
createcouple(pos, train, true, other_train, false)
break
end
end
end
end
@ -1013,20 +981,22 @@ function advtrains.train_check_couples(train)
if not train.cpl_back then
-- recheck back couple
local back_trains, pos = advtrains.occ.get_occupations(train, atround(train.end_index) - CPL_CHK_DST)
for tid, idx in pairs(back_trains) do
local other_train = advtrains.trains[tid]
if not advtrains.train_ensure_init(tid, other_train) then
atwarn("Train",tid,"is not initialized! Couldn't check couples!")
return
end
if other_train.velocity == 0 then
if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
createcouple(pos, train, false, other_train, true)
break
if minetest.get_node_or_nil(pos) then -- if the position is loaded...
for tid, idx in pairs(back_trains) do
local other_train = advtrains.trains[tid]
if not advtrains.train_ensure_init(tid, other_train) then
atwarn("Train",tid,"is not initialized! Couldn't check couples!")
return
end
if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
createcouple(pos, train, false, other_train, false)
break
if other_train.velocity == 0 then
if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
createcouple(pos, train, false, other_train, true)
break
end
if idx<=other_train.end_index and idx>=other_train.end_index - CPL_ZONE then
createcouple(pos, train, false, other_train, false)
break
end
end
end
end

View File

@ -432,17 +432,10 @@ function wagon:on_step(dtime)
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
train.velocity=math.min(train.velocity, 1)
else
train.recently_collided_with_env=true
train.velocity=0
self.collision_count=(self.collision_count or 0)+1
end
else
self.collision_count=nil
-- screw collision mercy
train.recently_collided_with_env=true
train.velocity=0
advtrains.atc.train_reset_command(train)
end
end

View File

@ -5,6 +5,9 @@ else
S = function(s,a,...)a={a,...}return s:gsub("@(%d+)",function(n)return a[tonumber(n)]end)end
end
-- length of the steam engine loop sound
local SND_LOOP_LEN = 5
advtrains.register_wagon("newlocomotive", {
mesh="advtrains_engine_steam.b3d",
textures = {"advtrains_engine_steam.png"},
@ -111,14 +114,20 @@ advtrains.register_wagon("detailed_steam_engine", {
self.object:set_animation({x=1,y=80}, advtrains.abs_ceil(velocity)*15, 0, true)
self.old_anim_velocity=advtrains.abs_ceil(velocity)
end
if velocity > 0 and not self.sound_loop_handle then
self.sound_loop_handle = minetest.sound_play({name="advtrains_steam_loop", gain=2}, {object = self.object, loop=true})
elseif velocity==0 then
if self.sound_loop_handle then
minetest.sound_stop(self.sound_loop_handle)
self.sound_loop_handle = nil
end,
custom_on_step=function(self, dtime)
if self:train().velocity > 0 then -- First make sure that the train isn't standing
if not self.sound_loop_tmr or self.sound_loop_tmr <= 0 then
-- start the sound if it was never started or has expired
self.sound_loop_handle = minetest.sound_play({name="advtrains_steam_loop", gain=2}, {object=self.object})
self.sound_loop_tmr = SND_LOOP_LEN
end
end
--decrease the sound timer
self.sound_loop_tmr = self.sound_loop_tmr - dtime
else
-- If the train is standing, the sound will be stopped in some time. We do not need to interfere with it.
self.sound_loop_tmr = nil
end
end,
custom_on_activate = function(self, staticdata_table, dtime_s)
minetest.add_particlespawner({