Page 1 of 1

[0.14.19] Glitchy LuaEntity.get_connected_rail method

Posted: Fri Nov 04, 2016 10:55 pm
by icedevml
Hello,

I want to use LuaEntity.get_connected_rail together with LuaTrain.front_rail and LuaTrain.rail_direction_from_front_rail. So in my mod I implemented the following algorithm (pseudocode):

Code: Select all

local front_rail = some_train.front_rail
local dir = some_train.rail_direction_from_front_rail
local n = 0
local path = {}

while n < 10 do
   table.insert(path, front_rail)
   front_rail = front_rail.get_connected_rail{rail_direction=dir, rail_connection_direction=defines.rail_connection_direction.straight}
   n = n+1
end
So at the end, "path" table was supposed to contain next 10 rail objects which are straight ahead. Everything works in case of rails placed in north, south, west and east direction. In case of rails placed in northeast, southeast etc. direction, incorrect values are returned every second time, so the path after performing above algorithm looks like this: { rail1, rail2, rail1, rail2, rail1, rail2 }.

For the first time it actually returns NEXT rail, but for the next time in the same direction it returns PREVIOUS rail o_O At the moment this method is kinda unusable due to this problem.

I could share some code or screenshots if needed.

Re: Glitchy LuaEntity.get_connected_rail method

Posted: Fri Nov 04, 2016 11:06 pm
by Loewchen
Please post a minimal working example, its output and the output you would expect. And please state the version of the game.

Re: Glitchy LuaEntity.get_connected_rail method

Posted: Fri Nov 04, 2016 11:11 pm
by icedevml
Steps to reproduce:

1. build some simple rail path without junctions
2. build a diesel locomotive and enter it
3. run the following lua function:

Code: Select all

function inspect_path()
    local train = game.player.vehicle.train
    
    local fr = train.front_rail
    local dir = train.rail_direction_from_front_rail
    
    local n = 0
    
    while n < 10 do
        local cr = fr.get_connected_rail{rail_direction=dir, rail_connection_direction=defines.rail_connection_direction.straight}
        game.player.print("#" .. n .. ": " .. cr.position.x .. " " .. cr.position.y)
        fr = cr

        n = n + 1
    end
end
Enclosed you may find three screenshots with the paths generated by above function. Situation on r1 screenshot is okay, while on r2 we could see a strange loop and on r3 it yields nil after approaching curved rail.

I would expect that the above code would give me next 10 consecutive rail entities which are ahead.

Tested with Factorio 0.14.16 and Factorio 0.14.19

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Posted: Sat Nov 05, 2016 3:46 am
by osldgoth
I think perhaps that is caused by the diagonal rails alternating direction, so you'll need to write your code to account for that (annoying)
Image

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Posted: Sat Nov 05, 2016 9:52 am
by icedevml
osldgoth wrote:I think perhaps that is caused by the diagonal rails alternating direction, so you'll need to write your code to account for that (annoying)
Image
I also realized that, regardless of how intuitive it is. Let's add a direction inverting in case of diagonal rails:

Code: Select all

function inspect_path()
    local train = game.player.vehicle.train
    
    local fr = train.front_rail
    local dir = train.rail_direction_from_front_rail
    
    local n = 0
    
    while n < 10 do    
        local cr = fr.get_connected_rail{rail_direction=dir, rail_connection_direction=defines.rail_connection_direction.straight}
        
        if cr.name == 'straight-rail' and cr.direction % 2 == 1 then
            if dir == defines.rail_direction.front then
                dir = defines.rail_direction.back
            else
                dir = defines.rail_direction.front
            end
        end
        
        game.player.print("#" .. n .. ": " .. cr.position.x .. " " .. cr.position.y)
        fr = cr

        n = n + 1
    end
end
So now it works if we have only straight rails or only diagonal rails. If there is a curved rail in the middle of path it works only sometimes.

I have trouble with understanding the philosophy and implementation details behind this and it's not documented at all.

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Posted: Sat Nov 05, 2016 10:07 am
by icedevml
Okay, I realized that in case of curved rail we have to go to the left or to the right. So the new inspect_path including that:

Code: Select all

function inspect_path()
    local train = game.player.vehicle.train
    
    local fr = train.front_rail
    local dir = train.rail_direction_from_front_rail
    
    local n = 0
    
    while n < 10 do  
        local rail_ahead = fr.get_connected_rail{rail_direction=dir, rail_connection_direction=defines.rail_connection_direction.straight}
        local rail_left = fr.get_connected_rail{rail_direction=dir, rail_connection_direction=defines.rail_connection_direction.left}
        local rail_right = fr.get_connected_rail{rail_direction=dir, rail_connection_direction=defines.rail_connection_direction.right}
        
        local use_rail = nil
        
        if rail_ahead and rail_left == nil and rail_right == nil then
            use_rail = rail_ahead
            game.player.print("#" .. n .. ": using ahead")
        elseif rail_left and rail_ahead == nil and rail_right == nil then
            use_rail = rail_left
            game.player.print("#" .. n .. ": using left")
        elseif rail_right and rail_ahead == nil and rail_left == nil then
            use_rail = rail_right
            game.player.print("#" .. n .. ": using right")
        else
            game.player.print("no path / junction detected, stopping")
            return nil
        end
        
        if (use_rail.name == 'straight-rail' and use_rail.direction % 2 == 1) then
            if dir == defines.rail_direction.front then
                dir = defines.rail_direction.back
            else
                dir = defines.rail_direction.front
            end
        end
        
        game.player.print("#" .. n .. ": " .. use_rail.position.x .. " " .. use_rail.position.y)
        fr = use_rail

        n = n + 1
    end
end
Still doesn't work when it comes to curved rail (or in some cases it works, in some does not). By not working I mean catching an infinite loop at the curved rail.

Probably according to this logic I have to write some condition for inverting direction in case of curved rails but I could not get a clear idea how to do that. I guess API should be more straightforward.

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Posted: Sun Nov 06, 2016 11:43 am
by Klonan
Thanks for the report,

However I can't see anything wrong with the Lua method, many other mods have used it an never had an issue,

So i will move this to not a bug...

If you find a specific issue with its usage, please make a new bug report

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Posted: Mon Nov 07, 2016 3:26 pm
by kovarex
The most simple way to iterate rails is: (pseudocode)

Code: Select all

local direction = (the direction I want to go)
local rail = (the initial rail).

local new_rail = rail.getNext(direction)
local new_direction = opposite_direction(direction_to_rail(new_rail, rail))

direction = new_direction
rail = new_rail

(repeat)

You just need the direction_to_rail method, which simply takes one rail, and tries to find out which connection connect it to the other rail.
Then you need the opposite_direction method, which is probably something like (x + 1)% 2