Event request: on_recipe_changed

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Post Reply
User avatar
lovely_santa
Filter Inserter
Filter Inserter
Posts: 502
Joined: Sat Feb 18, 2017 9:41 pm
Contact:

Event request: on_recipe_changed

Post by lovely_santa »

Hi RSeding,

I have to keep track of all my buildings that have a set recipe.
To keep track of the active recipes there are 3 options:
- When a player/bot places a building over a ghost that has a recipe set (easy)
- When a player uses the copy/paste setting (easy)
- When a player changes the recipe manualy (though).

On that last one, I can't look on_gui_closed becose the gui doesn't have to be explicitly closed by the player, when keeping track of the open gui of the player is very inefficient.

I think this is reason enough for this event?
Becose we might be able to check it when the gui is closed, but thats not the same time as when the player changes the recipe, for example, when the player resets the recipe, the player gains items in the input/output buffer of the machine, so we can't take action when that recipe changes (there is no on_inventory_changed event either that would give a perfect solution, but even then recipes could be changed at times that the player wouldn't gain items), so i realy think this is lacking some event handling...

Kind regards,
lovely_santa
Last edited by lovely_santa on Thu Jul 05, 2018 10:06 am, edited 4 times in total.
You can find all my mods on the mod portal. Also helping on Arch666Angel's mods.
Image

User avatar
Godmave
Long Handed Inserter
Long Handed Inserter
Posts: 89
Joined: Tue Nov 15, 2016 3:52 pm
Contact:

Re: Event request: on_recipe_changed

Post by Godmave »

Or enabling the close event for any closing, not just explicit, would help me (use_colors change for lamps) and probably others too.

Rseding91
Factorio Staff
Factorio Staff
Posts: 13173
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Event request: on_recipe_changed

Post by Rseding91 »

Why exactly do you want to track what machines have what recipe set?
If you want to get ahold of me I'm almost always on Discord.

User avatar
lovely_santa
Filter Inserter
Filter Inserter
Posts: 502
Joined: Sat Feb 18, 2017 9:41 pm
Contact:

Re: Event request: on_recipe_changed

Post by lovely_santa »

Yes, I want to track what an assembling machine type of entity has set as recipe. Depending on the recipe I need to take actions.
Once the machine is backed up, I can put the machine in a sleep-like mode, more like a code optimalisation. But when the recipe changes I have to take actions again. But there is no event (or series of events) that can give me real time information about the recipe beiing set/unset (mostly the set is an issue).

Thats why i want to have an event on_recipe_changed that holds the entity and player who changed the recipe. An optional parameter would be the recipe that has been set (or nil when it was removed), but that i can check on the entity itself, so that would be obsolete.

Kind regards,
lovely_santa
You can find all my mods on the mod portal. Also helping on Arch666Angel's mods.
Image

Rseding91
Factorio Staff
Factorio Staff
Posts: 13173
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Event request: on_recipe_changed

Post by Rseding91 »

But *why* do you want to do that?
If you want to get ahold of me I'm almost always on Discord.

User avatar
lovely_santa
Filter Inserter
Filter Inserter
Posts: 502
Joined: Sat Feb 18, 2017 9:41 pm
Contact:

Re: Event request: on_recipe_changed

Post by lovely_santa »

Becose when the assembler is done crafting something, i have to take actions (manualy removing output, placing stuff on the surface as result). When the recipe gets changed, i also have to remove placed down stuff.. Its for in a vehicle mod and also some robot mod

EDIT: afther discord conversation:
Why: I want to extend the output buffer behaviour of a machine, so it crafts some items up till the output buffer has some recipes build. At the end of that, i take some out and place an entity inside the world, that is part of the output buffer.

There are alredy events in place for copy/paste, placing/destroying entities, ghosts, but there are no events when the player changes the recipe manualy.
Klonan said that this was reasonable, but that I could set a fixed recipe.
I answered if there are some mods involved i would have to make a building for each available recipe, so that wouldn't be a solution.

Klonan found it a reasonable request, that could open up some possibilities, mainly of not hassling the game on_tick to see if te recipes are the same
  • Tracking recipes
  • When player sets special recipe, insert ingredients so its crafting automaticly
  • autofill when you change recipes (like the mod doiing it for turrets)
  • ...
I hope this answers the *why* question beter?
You can find all my mods on the mod portal. Also helping on Arch666Angel's mods.
Image

Rseding91
Factorio Staff
Factorio Staff
Posts: 13173
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Event request: on_recipe_changed

Post by Rseding91 »

Those reasons don't justify the performance overhead and maintenance to implement that event.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Mylon
Filter Inserter
Filter Inserter
Posts: 513
Joined: Sun Oct 23, 2016 11:42 pm
Contact:

Re: Event request: on_recipe_changed

Post by Mylon »

How often does a recipe change? The number of times such an event fires ought to be tiny. Maybe 10,000 calls throughout an entire game?

My particular usecase:

I made a scenario called Regional Production. Goods can only be produced near a matching marker. I want a on_recipe_changed event so I can say "Not allowed" and set the recipe to nil. As opposed to currently where I use a worker to iterate over all assemblers and if one has the wrong recipe I correct it them.

Rseding91
Factorio Staff
Factorio Staff
Posts: 13173
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Event request: on_recipe_changed

Post by Rseding91 »

The main issue is the added complexity to protect against mods doing 'things' during the event that can invalidate parts of the game.

Right now we don't have any protection in place around setting recipes in assembling machines because it's not possible for a mod to break anything. If I add an event then I need to go over every possible place in code where an assembling machine recipe can be set and make sure it properly handles if *anything* is invalidated/changed.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Mylon
Filter Inserter
Filter Inserter
Posts: 513
Joined: Sun Oct 23, 2016 11:42 pm
Contact:

Re: Event request: on_recipe_changed

Post by Mylon »

I'm confused. Aren't these protections already in place around LuaEntity.set_recipe()? I already can mess with the bits I need and this function seems to perform fine. I'm not sure how on_recipe_changed event would be any different than a very aggressive on_tick check_all_assemblers() function.

Rseding91
Factorio Staff
Factorio Staff
Posts: 13173
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Event request: on_recipe_changed

Post by Rseding91 »

This is (one of) the call stacks for how an assembling machine can have its recipe set:
> factorio-run.exe!CraftingMachine::setRecipeID(ID<RecipePrototype,unsigned short> recipeID, CraftingMachine::FromScript fromScript, CraftingMachine::RefreshEffect refreshEffect) Line 639 C++
factorio-run.exe!AssemblingMachine::setRecipeID(ID<RecipePrototype,unsigned short> recipeID, CraftingMachine::FromScript fromScript, CraftingMachine::RefreshEffect refreshEffect) Line 554 C++
factorio-run.exe!AssemblingMachine::setupForCrafting(ID<RecipePrototype,unsigned short> recipeID, InventoryBuffer & buffer, CraftingMachine::FromScript fromScript, AssemblingMachine::Force force) Line 403 C++
factorio-run.exe!AssemblingMachine::copyEntitySettings(const CopyEntitySettingsData & data) Line 468 C++
factorio-run.exe!BlueprintDataHandler::copyEntitySettings(Entity * equalEntity, const Entity * entity, const Direction direction) Line 185 C++
factorio-run.exe!BlueprintEntities::build::__l2::<lambda>(Entity * source, BuildCheckResult & buildableTest, Entity * entity) Line 464 C++
factorio-run.exe!BlueprintEntities::build(BlueprintDataHandler & dataHandler, const Vector & shift, Direction direction, bool altBuild, bool skipFogOfWar) Line 518 C++
factorio-run.exe!Blueprint::tryToBuild(BlueprintDataHandler & dataHandler, const MapPosition & position, Direction direction, bool altBuild, bool skipFogOfWar) Line 394 C++
factorio-run.exe!ManualBuilder::buildBlueprint(const MapPosition & placeToPut, Direction direction, BlueprintItem & blueprintItem, CreatedByMoving __formal, bool altBuild, bool skipFogOfWar) Line 1374 C++
factorio-run.exe!ManualBuilder::buildItem(const ActionData::BuildItemParameters & buildInfo, ForceID forceID, ID<EntityPrototype,unsigned short> rawEntityID, BuildItemSettings settings, UndoItem * undoItem) Line 575 C++
factorio-run.exe!CharacterController::buildItem(const ActionData::BuildItemParameters & buildInfo) Line 574 C++
factorio-run.exe!GameActionHandler::buildItem(const InputAction & event, Controller * controller) Line 634 C++
factorio-run.exe!GameActionHandler::actionPerformed(const InputAction & event) Line 305 C++
factorio-run.exe!InputHandler::flushToListeners(const InputAction & action, bool isStopped) Line 73 C++
factorio-run.exe!InputHandler::flushActions(bool isStopped, unsigned int tick) Line 65 C++
factorio-run.exe!InputHandler::nextTick(unsigned int tick) Line 53 C++
factorio-run.exe!GameActionHandler::update() Line 346 C++
factorio-run.exe!MainLoop::gameUpdateStep(MultiplayerManagerBase * multiplayerManagerBase, Scenario * scenario, AppManager * appManager, MainLoop::HeavyMode heavyMode) Line 1009 C++
factorio-run.exe!MainLoop::gameUpdateLoop(MainLoop::HeavyMode heavyMode) Line 881 C++
factorio-run.exe!MainLoop::mainLoopStep::__l2::<lambda>() Line 555 C++
[External Code]
factorio-run.exe!WorkerThread::loop() Line 42 C++
[External Code]
factorio-run.exe!invoke_thread_procedure(unsigned int(*)(void *) procedure, void * const context) Line 92 C++
factorio-run.exe!thread_start<unsigned int (__cdecl*)(void * __ptr64)>(void * const parameter) Line 115 C++
That's deep inside the build logic for building a blueprint. And that deep down it would then fire a Lua event which can invalidate any entity, any item, add or remove forces, and so on.

Every single site that calls into another function deep would need its own protection to check if everything is still valid after the function finished if that event existed.

Now compare that to the on_tick event:
> factorio-run.exe!LuaEventDispatcher::dispatch(unsigned int tick) Line 93 C++
factorio-run.exe!LuaContext::update() Line 130 C++
factorio-run.exe!Scenario::update() Line 1070 C++
factorio-run.exe!Scenario::updateStep() Line 970 C++
factorio-run.exe!MainLoop::gameUpdateStep(MultiplayerManagerBase * multiplayerManagerBase, Scenario * scenario, AppManager * appManager, MainLoop::HeavyMode heavyMode) Line 1016 C++
factorio-run.exe!MainLoop::gameUpdateLoop(MainLoop::HeavyMode heavyMode) Line 881 C++
factorio-run.exe!MainLoop::mainLoopStep::__l2::<lambda>() Line 555 C++
[External Code]
factorio-run.exe!WorkerThread::loop() Line 42 C++
[External Code]
factorio-run.exe!invoke_thread_procedure(unsigned int(*)(void *) procedure, void * const context) Line 92 C++
factorio-run.exe!thread_start<unsigned int (__cdecl*)(void * __ptr64)>(void * const parameter) Line 115 C++
[External Code]
It has nothing it needs to check. Regardless of what the on_tick handler does the game is left in a valid state and the code just returns having finished the event.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Mylon
Filter Inserter
Filter Inserter
Posts: 513
Joined: Sun Oct 23, 2016 11:42 pm
Contact:

Re: Event request: on_recipe_changed

Post by Mylon »

How about a different approach? What if recipe_changed toggled a flag on crafting machines and the event is raised in the next crafting_machine::update?

Also, following other events, LuaCraftingMachine.setRecipe() wouldn't raise the event much like how other lua calls don't raise events.

Rseding91
Factorio Staff
Factorio Staff
Posts: 13173
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Event request: on_recipe_changed

Post by Rseding91 »

Mylon wrote:
Sat Oct 06, 2018 3:01 pm
How about a different approach? What if recipe_changed toggled a flag on crafting machines and the event is raised in the next crafting_machine::update?

Also, following other events, LuaCraftingMachine.setRecipe() wouldn't raise the event much like how other lua calls don't raise events.
The machine would then need to store the fact the recipe changed + what the old recipe was in memory and in the save file. Neither of which are acceptable.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Mylon
Filter Inserter
Filter Inserter
Posts: 513
Joined: Sun Oct 23, 2016 11:42 pm
Contact:

Re: Event request: on_recipe_changed

Post by Mylon »

I wouldn't imagine an extra bool per crafting machine would be a big deal for the save. As for the previous recipe... I'm not sure that's necessary either. At least for my use case, all I need to know is if the current recipe follows a rule. Testing the machine periodically just in case the recipe changed makes the rule checking unresponsive.

Avacado
Long Handed Inserter
Long Handed Inserter
Posts: 94
Joined: Fri Jul 22, 2016 3:17 pm
Contact:

Re: Event request: on_recipe_changed

Post by Avacado »

To keep track of the active recipes there are 3 options:
- When a player/bot places a building over a ghost that has a recipe set (easy)
- When a player uses the copy/paste setting (easy)
- When a player changes the recipe manualy (though).

On that last one, I can't look on_gui_closed becose the gui doesn't have to be explicitly closed by the player, when keeping track of the open gui of the player is very inefficient.
I was considering implementing this same feature in my mod (Whistle Stop Factories) because I have map tags over each factory that indicates its current recipe. Currently I track a list of all of my factories and check them all on every nth tick.

If I were to capture these 3 events for creating these map tags, I'd miss recipe changes from recipes set by mods, but would I miss anything else? What do you mean by "the gui doesn't have to be explicitly closed by the player"? Are there situation in which the gui close event wouldn't be triggered?

I can't think of that many mods that set recipes. Crafting Combinator does, but I think it'd be fine to not support map tags for the rapidly changing recipes that mod produces. Are there any other mods that would cause a problem for me using this combination of triggers in place of the more ideal recipe_change?

User avatar
lovely_santa
Filter Inserter
Filter Inserter
Posts: 502
Joined: Sat Feb 18, 2017 9:41 pm
Contact:

Re: Event request: on_recipe_changed

Post by lovely_santa »

Avacado wrote:
Fri Oct 19, 2018 2:36 am

If I were to capture these 3 events for creating these map tags, I'd miss recipe changes from recipes set by mods, but would I miss anything else? What do you mean by "the gui doesn't have to be explicitly closed by the player"? Are there situation in which the gui close event wouldn't be triggered?
Yes there are multiple examples, one of them when you move out of reach and the gui closes on you... or when you get disconnected from the game, ...
You can find all my mods on the mod portal. Also helping on Arch666Angel's mods.
Image

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Event request: on_recipe_changed

Post by eradicator »

You could start a dynamic tick handler in on_gui_opened that continously watches player.opened until it is closed again. That way you don't need to care about the source of the window closing. And you only need to check at most $number_of_players or $number_of_connected_players per tick. And 0 when no factory guis are open.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.

Xorimuth
Filter Inserter
Filter Inserter
Posts: 623
Joined: Sat Mar 02, 2019 9:39 pm
Contact:

Re: Event request: on_recipe_changed

Post by Xorimuth »

I'd also be interested in seeing this implemented, although the work-arounds suggested seem quite comprehensive.

Edit: I no longer need this
Last edited by Xorimuth on Fri Apr 08, 2022 2:27 am, edited 1 time in total.
My mods
Content: Freight Forwarding | Spidertron Patrols | Spidertron Enhancements | Power Overload
QoL: Factory Search | Remote Configuration | Module Inserter Simplified | Wire Shortcuts X | Ghost Warnings

Xorimuth
Filter Inserter
Filter Inserter
Posts: 623
Joined: Sat Mar 02, 2019 9:39 pm
Contact:

Re: Event request: on_recipe_changed

Post by Xorimuth »

Xorimuth wrote:
Thu Mar 31, 2022 11:50 am
I'd also be interested in seeing this implemented, although the work-arounds suggested seem quite comprehensive.
So the main thing I've found impossible/very hacky to deal with is using blueprints on already-built assemblers to change their recipe. This only raises on_pre_built, which doesn't have enough information to reliably work out which recipes have been changed (particularly when it is a blueprint library blueprint which are invisible to the mod). :(
My mods
Content: Freight Forwarding | Spidertron Patrols | Spidertron Enhancements | Power Overload
QoL: Factory Search | Remote Configuration | Module Inserter Simplified | Wire Shortcuts X | Ghost Warnings

Post Reply

Return to “Modding interface requests”