[boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

This subforum contains all the issues which we already resolved.
Post Reply
Dreamer
Manual Inserter
Manual Inserter
Posts: 4
Joined: Sat Nov 30, 2019 10:33 am
Contact:

[boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by Dreamer »

code:

Code: Select all

for i = 1,#machine.fluidbox do
    game.print(i.." ".. machine.fluidbox.get_prototype(i).base_level .. " " .. machine.fluidbox.get_prototype(i).production_type)
end
correct result for "Advanced oil processing":
1 -1 input
2 -1 input
3 1 output
4 1 output
5 1 output

unexpected result for "Basic oil processing"
1 -1 input
2 -1 input -- wrong: output expected

Edit:
My post seems to be a duplicate (sorry. didn't see it). Bug is known and sorted under "won't fix".
viewtopic.php?f=58&t=88092

But can you please update the documentation for get_prototype:
https://lua-api.factorio.com/latest/LuaFluidBox.html

and please tell me a workaround how I can find out if a fluidbox of a crafting machine is an input or an output.

robot256
Filter Inserter
Filter Inserter
Posts: 560
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: [1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by robot256 »

Join my thread over in Modding Interface Requests... viewtopic.php?f=28&t=100681

The thing that makes this a bug, and which Rseding did not address when closing the 2020 bug report, is that `LuaFluidBox::get_prototype(n)` validates the range of `n` based on the number of runtime fluidboxes, rather than the number of prototype fluidboxes--but still returns the nth prototype from the original prototype list. If there are fewer runtime than prototype fluidboxes, it prevents you from reading the complete prototype list.

If this were corrected, then mods could theoretically do their own work to figure out which prototype fluidbox(es) map to which runtime fluidboxes. As it is, we do not get access to enough information to even try. Alternatively, the devs could simply delete the LuaFluidBox::get_prototype(n) from the API, since it does not work as advertised or in any consistent manner, so we can stop wasting time with it.

Dreamer
Manual Inserter
Manual Inserter
Posts: 4
Joined: Sat Nov 30, 2019 10:33 am
Contact:

Re: [1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by Dreamer »

robot256 wrote:
Thu Feb 23, 2023 12:20 am
Alternatively, the devs could simply delete the LuaFluidBox::get_prototype(n) from the API, since it does not work as advertised or in any consistent manner, so we can stop wasting time with it.
I agree. Before that it would be nice to add a line in the api documentation informing about this bug

User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 1983
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by boskid »

Most of the issues related to prototypes of fluidboxes of an assembling machine are related to the incompatibility of assumptions between what we can do on the lua side and how the FluidBoxManager works.

Most of the Lua*Prototype objects store an ID related to the prototype so those objects can be correctly save-loaded and migrated when changing mods. LuaFluidBoxPrototype object is also following that logic as it stores the EntityID which makes it possible to get correct EntityPrototype and find the required fluidbox prototypes. LuaFluidBoxPrototype also stores the index of the fluidbox prototype as a single entity prototype may have multiple fluidbox prototypes included and that object must point at a correct one when save-loaded.

Assembling machines (or more specifically CraftingMachines which includes both Assemblers[selectable recipe] and Furnaces[automatic recipe]) are using a FluidBoxManager object which makes those objects able to change the layout of fluidboxes, specifically by removing unused fluidboxes, merging other fluidboxes, selecting fluidboxes etc based on the extra data provided from the recipe. In order to fit into the FluidBox system, that object creates a temporary prototypes (internally called FluidBoxPrototypeCompound) which are owned by the particular instances of the entities on the map. Those temporary prototypes have all connections of prototypes selected by the recipe. Unfortunately those temporary prototypes are nowere to be seen inside of the EntityPrototype and as such it is not possible to create a LuaFluidBoxPrototype object for a compound fluidbox of a crafting machine.

I will take a look what could be done to fill the gap. Most likely i will have to change the LuaFluidBox::get_prototype slightly. There are 3 options possible:
1/ make the LuaFluidBoxPrototype able to point to a temporary prototype by specifying a targeter to a real entity and its fluidbox index. This has some challenges because those temporary prototypes can be deleted at any point in time and LuaFluidBoxPrototype assumes a prototype is never deleted.
2/ add an alternative object LuaFluidBoxPrototypeCompound that would be only ever able to target a real entity, would not assume prototype is never deleted and would expose a specific api for reading the compound prototype. This is relatively ugly solution because it is a lot of code duplication related to the lua api
3/ make the LuaFluidBox::get_prototype able to return a table of prototypes from which a compound prototype was constructed.

So far only option 3 seems reasonable so i will try that solution.

User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 1983
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by boskid »

Ok i think the solution with a table is relatively reasonable. I have following lua command that i am using for my checks:

Code: Select all

/c
  local fb = game.player.selected.fluidbox
  local s = #fb
  log("Selected entity: "..game.player.selected.name)
  log("Recipe: "..game.player.selected.get_recipe().name)
  for i = 1,s do
    local prototype = fb.get_prototype(i)
    log("FluidBox "..i..":")

    if not prototype.__self then
      for _,p in pairs(prototype) do
        log(serpent.line(p.pipe_connections))
      end
    else
      log(serpent.line(prototype.pipe_connections))
    end
  end
and it seems to work relatively nice (the only annoying part is that LuaObjects in 1.1.x are also tables so a `type(x) == "table"` check was also throwing when a single prototype was returned (in 1.2 all LuaObjects will report as type(..)=="userdata"). Those are the outcomes i got for some machines and some recipes:

Code: Select all

Selected entity: chemical-plant
Recipe: heavy-oil-cracking
FluidBox 1:
{{positions = {{x = -1, y = -2}, {x = 2, y = -1}, {x = 1, y = 2}, {x = -2, y = 1}}, type = "input"}}
FluidBox 2:
{{positions = {{x = 1, y = -2}, {x = 2, y = 1}, {x = -1, y = 2}, {x = -2, y = -1}}, type = "input"}}
FluidBox 3:
{{positions = {{x = -1, y = 2}, {x = -2, y = -1}, {x = 1, y = -2}, {x = 2, y = 1}}, type = "output"}}
{{positions = {{x = 1, y = 2}, {x = -2, y = 1}, {x = -1, y = -2}, {x = 2, y = -1}}, type = "output"}}

Code: Select all

Selected entity: oil-refinery
Recipe: basic-oil-processing
FluidBox 1:
{{positions = {{x = 1, y = 3}, {x = -3, y = 1}, {x = -1, y = -3}, {x = 3, y = -1}}, type = "input"}}
FluidBox 2:
{{positions = {{x = 2, y = -3}, {x = 3, y = 2}, {x = -2, y = 3}, {x = -3, y = -2}}, type = "output"}}

Code: Select all

Selected entity: oil-refinery
Recipe: advanced-oil-processing
FluidBox 1:
{{positions = {{x = -1, y = 3}, {x = -3, y = -1}, {x = 1, y = -3}, {x = 3, y = 1}}, type = "input"}}
FluidBox 2:
{{positions = {{x = 1, y = 3}, {x = -3, y = 1}, {x = -1, y = -3}, {x = 3, y = -1}}, type = "input"}}
FluidBox 3:
{{positions = {{x = -2, y = -3}, {x = 3, y = -2}, {x = 2, y = 3}, {x = -3, y = 2}}, type = "output"}}
FluidBox 4:
{{positions = {{x = 0, y = -3}, {x = 3, y = 0}, {x = -0, y = 3}, {x = -3, y = -0}}, type = "output"}}
FluidBox 5:
{{positions = {{x = 2, y = -3}, {x = 3, y = 2}, {x = -2, y = 3}, {x = -3, y = -2}}, type = "output"}}

Code: Select all

Selected entity: chemical-plant
Recipe: sulfuric-acid
FluidBox 1:
{{positions = {{x = -1, y = -2}, {x = 2, y = -1}, {x = 1, y = 2}, {x = -2, y = 1}}, type = "input"}}
{{positions = {{x = 1, y = -2}, {x = 2, y = 1}, {x = -1, y = 2}, {x = -2, y = -1}}, type = "input"}}
FluidBox 2:
{{positions = {{x = -1, y = 2}, {x = -2, y = -1}, {x = 1, y = -2}, {x = 2, y = 1}}, type = "output"}}
{{positions = {{x = 1, y = 2}, {x = -2, y = 1}, {x = -1, y = -2}, {x = 2, y = -1}}, type = "output"}}

Code: Select all

Selected entity: chemical-plant
Recipe: solid-fuel-from-light-oil
FluidBox 1:
{{positions = {{x = -1, y = -2}, {x = 2, y = -1}, {x = 1, y = 2}, {x = -2, y = 1}}, type = "input"}}
{{positions = {{x = 1, y = -2}, {x = 2, y = 1}, {x = -1, y = 2}, {x = -2, y = -1}}, type = "input"}}

User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 1983
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by boskid »

Ok. This is now fixed for 1.1.77 and it consists of 2 changes: it was returning LuaFluidBoxPrototype references to wrong prototypes (in case of the basic-oil-processing) and it was unable to return a table of prototypes that are part of the compound (in case of the chemical-plant with "heavy-oil-cracking" recipe).

Dreamer
Manual Inserter
Manual Inserter
Posts: 4
Joined: Sat Nov 30, 2019 10:33 am
Contact:

Re: [boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by Dreamer »

This looks awesome. Thank you. :D

Dreamer
Manual Inserter
Manual Inserter
Posts: 4
Joined: Sat Nov 30, 2019 10:33 am
Contact:

Re: [boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by Dreamer »

boskid wrote:
Thu Feb 23, 2023 12:11 pm
in 1.2 all LuaObjects will report as type(..)=="userdata"
Wait a moment. Is this just a small change in the type(..)-method or is this a massive code change with huge performance gains for mods? :o

User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 1983
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by boskid »

Dreamer wrote:
Thu Feb 23, 2023 2:50 pm
boskid wrote:
Thu Feb 23, 2023 12:11 pm
in 1.2 all LuaObjects will report as type(..)=="userdata"
Wait a moment. Is this just a small change in the type(..)-method or is this a massive code change with huge performance gains for mods? :o
I was not checking performance changes here, from the c++ side it behaves basically the same as lua table (there is a metatable that has to be set to the userdata object), primary gains are using "userdata" objects its easier to type check data if they are table or objects, it prevents doing rawset and rawget on the object and on c++ side its easier to keep object attached data in a memory managed by lua gc. Nothing to worry before 1.2 release, its one of many mod breaking changes that will be introduced in future by that major release.

robot256
Filter Inserter
Filter Inserter
Posts: 560
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: [boskid][1.1.76] calling LuaEntity.fluidbox.get_prototype(index) sometimes returns wrong prototype.

Post by robot256 »

boskid wrote:
Thu Feb 23, 2023 12:38 pm
Ok. This is now fixed for 1.1.77 and it consists of 2 changes
Thank you for addressing this! Hopefully this will resolve my interface request as well.

Post Reply

Return to “Resolved Problems and Bugs”