[Lou][2.0.13] Inconsistent behaviour (belt vs others) when changing ghost entity force during super-forced builds

Bugs that are actually features.
azaghal
Inserter
Inserter
Posts: 42
Joined: Sat Jun 27, 2020 11:13 am
Contact:

[Lou][2.0.13] Inconsistent behaviour (belt vs others) when changing ghost entity force during super-forced builds

Post by azaghal »

Description
When a player tries to do a super-forced build over existing ghost entities, there is a difference in behaviour, depending on ghost type, when the ghost entity's force is changed during the on_built_entity event.

Described scenario is a bit unusual, and probably not something that most mods deal with, but comes into play due to Construction Planner Continued's (mis)use of the modding API and force ownership. The mod changes the ghost force as part of the on_builty_entity event to prevent bots from the original (player) force constructing the ghost.

Since it is a bit hard for me to write this as reproduction steps, I will try to provide a little bit of code with some print statements to demonstrate the differences. I will focus on transport belt and underground pipes (as good examples).

Code: Select all

-- Set-up an allied force to the player's own - so we can easily see the placed ghosts when their force ownership is
-- changed.
local function create_not_player_force()
    local player_force = game.forces["player"]
    local not_player_force = game.create_force("not-player")

    player_force.set_friend(not_player_force, true)
    player_force.set_cease_fire(not_player_force, true)

    not_player_force.set_friend(player_force, true)
    not_player_force.set_cease_fire(player_force, true)
end

-- Switches force ownership for all placed entities (although primary interest is the ghost entities) to non-player
-- (allied) force as they are placed.
local function on_built_entity(event)
    local entity = event.entity

    local player_force = game.forces["player"]
    local not_player_force = game.forces["not-player"]
    
    print("Entity valid (pre-force change): " .. serpent.line(entity.valid) .. " @" .. game.tick)
    print("Entity unit number: " .. entity.unit_number .. " @" .. game.tick)
    print("Entity ghost name: " .. entity.ghost_name .. " @" .. game.tick)

    entity.force = not_player_force

    print("Entity valid (post-force change): " .. serpent.line(entity.valid) .. " @" .. game.tick)
end

script.on_init(create_not_player_force)

script.on_event(defines.events.on_built_entity, on_built_entity)
Underground pipe behaviour
With the above code, we can proceed to place the initial underground pipe ghost, which results in the following output:

Code: Select all

Entity valid (pre-force change): true @998
Entity unit number: 24 @998
Entity ghost name: pipe-to-ground @998
Entity valid (post-force change): true @998
After that, rotate the underground pipe so it is facing opposite direction of the initial one (game actually does this for us automatically, but just to emphasize that the underground pipe ghost placement attempt should not have the same orientation as the first one). Then try to super-force build on top of the existing pipe (which belongs to the other force at this point):

Code: Select all

Entity valid (pre-force change): true @13656
Entity unit number: 68 @13656
Entity ghost name: pipe-to-ground @13656
Entity valid (post-force change): true @13656
Couple of interesting things here:
  • It was possible to place down another underground pipe in the same spot.
  • The new underground pipe ghost entity remained valid after placement.
Transport belt behaviour
In the similar way to the above, place down a transport belt ghost:

Code: Select all

Entity valid (pre-force change): true @21088
Entity unit number: 82 @21088
Entity ghost name: transport-belt @21088
Entity valid (post-force change): true @21088
And then proceed to super-force place down the transport belt again on top of the existing one, but rotated by 180 degrees (similar to the underground pipe step):

Code: Select all

Entity valid (pre-force change): true @26422
Entity unit number: 106 @26422
Entity ghost name: transport-belt @26422
Entity valid (post-force change): false @26422
And here we can observe the following:
  • It was not possible to place two transport belt ghost entities in the same spot.
  • The newly placed entity seems to get immediately invalidated upon changing its force.
Conclusion?
So... It feels to me like only one of the two listed examples is the correct behaviour - or the very least that there is some kind of special logic that is handling transport belts etc in a bit of a different way. Would this be considered even as a bug in the game engine?

For me personally the behaviour of the underground pipe is maybe easier to handle (it kinda works out for my mod), but on the other hand... I'm pretty sure it is not normal to be able to have four ghost underground pipes (each facing its own direction) on a single tile...
Additional information
The reason I ended-up exploring this problem is because of a crash report for the Construction Planner Continued. While I have filed this under the bug reports, it might as well be intended behaviour or simply an implementation limitation/detail - but I wanted to at least double-check before I end-up trying to implement some kind of workaround in the mod.

I am also kinda curious what kind of oddities one could encounter

P.S.
Yours truly,
Doing-weird-things-with-your-game-engine
azaghal
Inserter
Inserter
Posts: 42
Joined: Sat Jun 27, 2020 11:13 am
Contact:

Re: [Lou][2.0.13] Inconsistent behaviour (belt vs others) when changing ghost entity force during super-forced builds

Post by azaghal »

In the meantime I have figured out why the crash started to happen in the mod - there were some changes to event properties that I did not adjust the code for - so some of the code that was supposed to switch back the force for unapproved ghost just before a new ghost gets pasted in never kicked in.

The report is still valid on the inconsistent behaviour thing, and I have thanks to another bug testing reported realised that certain ghost entities can be stacked on top of each-other for the same force.

For example, you could run this in console to get multiple inserter ghosts placed in same position for the same force:

Code: Select all

/c game.player.surface.create_entity{name = "entity-ghost", inner_name = "inserter", position = {20,15}, force = game.player.force}
In fact, looks like you can even stack different entities this way (like pipe + inserter). If you bot-build one inserter, the other ghost will be gone. But... If you place multiple car/spidetron ghosts in similar manner, even when one of them gets built, the other ghost remains on top.

Hopefully this extra info helps a bit. :)

P.S.
I also fixed the URLs in the report (nothing else changed, it was just messing with my "OCD").
User avatar
Lou
Factorio Staff
Factorio Staff
Posts: 342
Joined: Mon Nov 30, 2020 10:50 am
Contact:

Re: [Lou][2.0.13] Inconsistent behaviour (belt vs others) when changing ghost entity force during super-forced builds

Post by Lou »

Thank you for the reports.

Firstly - we allow more general freedom for commands, so being able to place colliding entities is not a bug.

The different behaviour for belts vs other entities is real, the reason is that because of various belt related logic, it is really useful to not allow multiple belts on the same position, and therefore have some extra buildability checks that destroys the belt when lua attempts to change its force. IMO trying to fix this case is asking for more trouble than its worth, so I would mark this as won't fix.

I am a bit confused about the mentioned crashes, but they seem to be resolved, right?
azaghal
Inserter
Inserter
Posts: 42
Joined: Sat Jun 27, 2020 11:13 am
Contact:

Re: [Lou][2.0.13] Inconsistent behaviour (belt vs others) when changing ghost entity force during super-forced builds

Post by azaghal »

Lou wrote: Thu Apr 09, 2026 4:15 pm Thank you for the reports.

Firstly - we allow more general freedom for commands, so being able to place colliding entities is not a bug.

The different behaviour for belts vs other entities is real, the reason is that because of various belt related logic, it is really useful to not allow multiple belts on the same position, and therefore have some extra buildability checks that destroys the belt when lua attempts to change its force. IMO trying to fix this case is asking for more trouble than its worth, so I would mark this as won't fix.
What does "fixing" mean in this particular context for you? Making the belt-like behaviour the default or making the underground pipe behaviour the default?
Lou wrote: Thu Apr 09, 2026 4:15 pm I am a bit confused about the mentioned crashes, but they seem to be resolved, right?
It has been a long time since I posted this, but the crash was probably just related to my own mod's logic at that time, so basically nothing that needs fixing on the game engine side (and I assume it was a "soft" crash, not the whole game engine going kaput).

Best regards,
Branko
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 4566
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [Lou][2.0.13] Inconsistent behaviour (belt vs others) when changing ghost entity force during super-forced builds

Post by boskid »

I am going to reclassify this bug report "Wont fix" into "Not a bug" to avoid unnecesary discussion in the future.

As mentioned earlier, placing colliding entities by script is usually allowed if its not causing other problems. With pipes it does not cause problems. In case of belts there are serious problems related to save-load stability since we do not save connections between neighbour belt pieces and as such if there is ambiguity about entity connections, it will cause a desync. Because of that there can either be only 1 real (non ghost) belt connectable on a tile, or there can be multiple ghosts as long as each one has different force (this does not cause save load stability problems because ghosts can only connect to other ghosts of the same force and with this extra equal-force condition there is only at most one of each; and only ghost of equal force will interact with real belt on adjacent tile). By changing force of a ghost if this restriction is broken then some entities may get removed.

Just because behavior is different does not mean it is a bug. There are simply additional constraints that are enforced during various operations. Similarily you cannot have multiple rails on top if they would have matching connection point with matching turn, or you could have item entities invalidated when placing a belt because it may try to put items from ground and add them onto lines.
Post Reply

Return to “Not a bug”