[0.14.19] Glitchy LuaEntity.get_connected_rail method

Bugs that are actually features.
icedevml
Burner Inserter
Burner Inserter
Posts: 12
Joined: Sun Jul 03, 2016 1:13 pm
Contact:

[0.14.19] Glitchy LuaEntity.get_connected_rail method

Post 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.
Last edited by icedevml on Sat Nov 05, 2016 12:02 am, edited 2 times in total.
Loewchen
Global Moderator
Global Moderator
Posts: 9287
Joined: Wed Jan 07, 2015 5:53 pm
Contact:

Re: Glitchy LuaEntity.get_connected_rail method

Post by Loewchen »

Please post a minimal working example, its output and the output you would expect. And please state the version of the game.
icedevml
Burner Inserter
Burner Inserter
Posts: 12
Joined: Sun Jul 03, 2016 1:13 pm
Contact:

Re: Glitchy LuaEntity.get_connected_rail method

Post 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
Attachments
r3_error.png
r3_error.png (1.95 MiB) Viewed 2750 times
r2_loop.png
r2_loop.png (1.96 MiB) Viewed 2750 times
r1_ok.png
r1_ok.png (1.93 MiB) Viewed 2750 times
osldgoth
Long Handed Inserter
Long Handed Inserter
Posts: 93
Joined: Thu Feb 26, 2015 3:52 am
Contact:

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Post 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
icedevml
Burner Inserter
Burner Inserter
Posts: 12
Joined: Sun Jul 03, 2016 1:13 pm
Contact:

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Post 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.
icedevml
Burner Inserter
Burner Inserter
Posts: 12
Joined: Sun Jul 03, 2016 1:13 pm
Contact:

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Post 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.
User avatar
Klonan
Factorio Staff
Factorio Staff
Posts: 5290
Joined: Sun Jan 11, 2015 2:09 pm
Contact:

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Post 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
kovarex
Factorio Staff
Factorio Staff
Posts: 8207
Joined: Wed Feb 06, 2013 12:00 am
Contact:

Re: [0.14.19] Glitchy LuaEntity.get_connected_rail method

Post 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
Post Reply

Return to “Not a bug”