Efficient way to get the LuaObject again for a known entity?

Place to get help with not working mods / modding interface.
Post Reply
cromptank
Manual Inserter
Manual Inserter
Posts: 4
Joined: Wed Dec 06, 2023 5:36 am
Contact:

Efficient way to get the LuaObject again for a known entity?

Post by cromptank »

I am currently storing some tables with information to find entities again, i.e.

spawner = game.surfaces[spawner_info.surface].find_entity(spawner_info.name, spawner_info.position)

Unless I am mistaken, I don't believe I can store LuaObjects in a subtable within the global table.
I don't know how many of these objects will exist, so I need them in a table.
The only way I found to locate them again is by using the LuaSurface.find() method, but this seems inefficient and I'd like to reduce any excessive processing cost in a mod I am working on.

mrvn
Smart Inserter
Smart Inserter
Posts: 5710
Joined: Mon Sep 05, 2016 9:10 am
Contact:

Re: Efficient way to get the LuaObject again for a known entity?

Post by mrvn »

The LuaGame object can find trains by ID but I think that's the only thing it can find by ID.

For all other cases you can simply keep the LuaEntity. It will always connect to the game object as long as that exists. You have to use

https://lua-api.factorio.com/latest/cla ... html#valid

to make sure the game entity sill exists later on though. In fact all Lua objects have a valid method.

Now you just have to consider if the memory overhead of the full LuaEntity is worse than the cost of finding the entity as needed. Also find might return a different entity. E.g. you store the position of a belt. But the user removes the belt and builds a new belt in it's place. Now find will return the new belt instead and you have no way of knowing.

Pi-C
Smart Inserter
Smart Inserter
Posts: 1654
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: Efficient way to get the LuaObject again for a known entity?

Post by Pi-C »

cromptank wrote:
Wed Dec 06, 2023 5:45 am
Unless I am mistaken, I don't believe I can store LuaObjects in a subtable within the global table.
As far as I know, you are not allowed to store functions in your global table, but storing entities is not a problem (or most of my mods would be broken). I may be wrong, but I believe you don't really store the entity, but rather a pointer to that entity, so there shouldn't be too much overhead.
I don't know how many of these objects will exist, so I need them in a table.
The only way I found to locate them again is by using the LuaSurface.find() method, but this seems inefficient and I'd like to reduce any excessive processing cost in a mod I am working on.
According to the documentation, LuaSurface::find() will "[f]ind an [emphasis mine] entity of the given type at the given position." I've run a short test:

Code: Select all

/c p= game.player pos = p.position bpos = {pos.x - 10, pos.y}
/c for i = 1, 3 do box = p.surface.create_entity{name = "wooden-chest", position = bpos} game.print(string.format("Box %s: %s", i, box.unit_number)) end
/c for i = 1, 10 do found = p.surface.find_entity("wooden-chest", bpos)  game.print(string.format("Result %s: %s", i,  found.unit_number)) end
/c found = p.surface.find_entities_filtered({name = "wooden-chest", position = bpos}) for i = 1, #found do game.print(string.format("Result %s: %s", i, found[i].unit_number)) end
It seems that LuaSurface::find() will find only the entity that was created last at the given position. LuaSurface:find_entities_filtered will find all entities, with the entity created last as first and the entity created first as last result. (If you mine an entity from a position where multiple entities of the same type are stacked, this will remove all of them.) This could be important with mods that create entities via script.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

Qon
Smart Inserter
Smart Inserter
Posts: 2118
Joined: Thu Mar 17, 2016 6:27 am
Contact:

Re: Efficient way to get the LuaObject again for a known entity?

Post by Qon »

cromptank wrote:
Wed Dec 06, 2023 5:45 am
Unless I am mistaken, I don't believe I can store LuaObjects in a subtable within the global table.
You are mistaken.
https://lua-api.factorio.com/latest/auxiliary/global.html wrote:Only specific data can be stored in global:
  • Basic data: nil, strings, numbers, booleans.
  • Tables, with limited metatables:
    • The metatable itself will not be saved.
    • Metatables that are registered with LuaBootstrap::register_metatable will be recorded by name and automatically relinked to the registered table on loading.
    • Any other metatables will be removed; tables with unregistered metatables become plain tables when saved and loaded.
  • References to Factorio's LuaObjects.
Functions are not allowed in global and will throw an error when saving.

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

Re: Efficient way to get the LuaObject again for a known entity?

Post by boskid »

Storage of LuaObjects in `global` is the intended way of keeping references between ticks. They hook into targeters system game uses so they are fast when used and compact when saved.

For me the title of this topic is a red flag: a known entity means you already have LuaObject to it (as this is the only unambiguous solution that does not need performing additional searches) so it reads as following: "Efficient way to get the LuaObject again for a known LuaObject".

mrvn
Smart Inserter
Smart Inserter
Posts: 5710
Joined: Mon Sep 05, 2016 9:10 am
Contact:

Re: Efficient way to get the LuaObject again for a known entity?

Post by mrvn »

boskid wrote:
Wed Dec 06, 2023 10:06 am
Storage of LuaObjects in `global` is the intended way of keeping references between ticks. They hook into targeters system game uses so they are fast when used and compact when saved.

For me the title of this topic is a red flag: a known entity means you already have LuaObject to it (as this is the only unambiguous solution that does not need performing additional searches) so it reads as following: "Efficient way to get the LuaObject again for a known LuaObject".
I think the subject was mend to be: Efficient way to get the LuaObject again for a previously known entity?

cromptank
Manual Inserter
Manual Inserter
Posts: 4
Joined: Wed Dec 06, 2023 5:36 am
Contact:

Re: Efficient way to get the LuaObject again for a known entity?

Post by cromptank »

mrvn wrote:
Wed Dec 06, 2023 1:48 pm
I think the subject was mend to be: Efficient way to get the LuaObject again for a previously known entity?
Nope. I have the LuaObject eariler in the code, and just want to access the same object again, so my question has been thoroughly answered. I had the impression that LuaObject was a class that could be stored in the global table as a copy of the in-game LuaObject. The first LuaObjects I was trying to keep track of were unit_group entities, and I likely got confused by them becoming invalid for various reasons, and not understanding the set_command() method which made them seem unresponsive. I ended up scrapping storing LuaObjects in the global table and have been using workarounds like the find function. I hurt myself in my own confusion...

Thanks for the help all! For a hopefully more informed followup question: If having a LuaObject is stored as a pointer in the global table I can access all of it's information, but there is some cost in accessing it. Is that cost greater than accessing information directly stored the global table? For example if I access a global table stored copy of an entity's position, is that faster, (slower?), or about the same as LuaObject.position?

mrvn
Smart Inserter
Smart Inserter
Posts: 5710
Joined: Mon Sep 05, 2016 9:10 am
Contact:

Re: Efficient way to get the LuaObject again for a known entity?

Post by mrvn »

cromptank wrote:
Wed Dec 06, 2023 3:15 pm
mrvn wrote:
Wed Dec 06, 2023 1:48 pm
I think the subject was mend to be: Efficient way to get the LuaObject again for a previously known entity?
Nope. I have the LuaObject eariler in the code, and just want to access the same object again, so my question has been thoroughly answered. I had the impression that LuaObject was a class that could be stored in the global table as a copy of the in-game LuaObject. The first LuaObjects I was trying to keep track of were unit_group entities, and I likely got confused by them becoming invalid for various reasons, and not understanding the set_command() method which made them seem unresponsive. I ended up scrapping storing LuaObjects in the global table and have been using workarounds like the find function. I hurt myself in my own confusion...

Thanks for the help all! For a hopefully more informed followup question: If having a LuaObject is stored as a pointer in the global table I can access all of it's information, but there is some cost in accessing it. Is that cost greater than accessing information directly stored the global table? For example if I access a global table stored copy of an entity's position, is that faster, (slower?), or about the same as LuaObject.position?
As I understand it the LuaObject is just the pointer. Whether you store it in a local variable or the global table makes no difference. There is no magic going on to store stuff in the global table. There is only magic for saving and loading the global table.

Your question should then be: Is it better to store the object and use object.position or use object.position once and store that.

Post Reply

Return to “Modding help”