Event when blueprint is rotated/flipped

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Post Reply
safthelamb@gmail.com
Burner Inserter
Burner Inserter
Posts: 10
Joined: Tue Aug 22, 2023 8:45 am
Contact:

Event when blueprint is rotated/flipped

Post by safthelamb@gmail.com »

Hi Devs!

I am creating a mod for configuring pipe flow, very similar interface to Inserter Configuration (https://mods.factorio.com/mod/Inserter_Config), and I have it 99.9% working! that said... I had a massive oversight in that pipes don't have a direction, can't be configured as rotatable at all, and even the ghost entity placed by blueprints with them don't have a rotation. This has been completely fine till now... except for rotating blueprints. Now, the mod Flow Control exists (https://mods.factorio.com/mod/Flow%20Control), and they way that mod works is by creating custom items for each pipe junction type and letting you rotate them, which would obviously work better for blueprints... but there are a handful of limitations and drawbacks of this, such as underground pipes not auto-removing pipes when replacing sections (which I've tested and does work when the entities are pipes!).

If there was an event for when a blueprint is rotated/flipped, and things like "can this blueprint be flipped" could be configured (right now you aren't allowed to flip blueprints with the custom pipes I've added, even though I could easily fix it up if I had the event), all I would really need is the ability to change the name of the entity within the blueprint to place, given which modifications were done to the blueprint.

I would gladly elaborate further or discuss alternative solutions, and would be happy to share the code for the mod as-is! It looks like there is some concept and precedent for exposing a non-trivial amount of blueprint info to lua (https://lua-api.factorio.com/latest/cla ... t_entities), so I'm hoping this request wouldn't be too significant an undertaking :)

Best!
SafTheLamb

safthelamb@gmail.com
Burner Inserter
Burner Inserter
Posts: 10
Joined: Tue Aug 22, 2023 8:45 am
Contact:

Re: Event when blueprint is rotated/flipped

Post by safthelamb@gmail.com »

Hi Devs and Modders!

If you're reading this, I figured out how to actually implement this! Unfortunately it is a massive ordeal, and I haven't plunged the depths of it quite yet, but I plan on doing so and putting it into a utility mod for others to use unless official support for this is planned.

After looking at the API docs for CustomInputPrototype, I noticed a parameter I hadn't seen before: linked_game_control (https://lua-api.factorio.com/latest/pro ... me_control). This is actually quite perfect, thank you devs!! With this, we can hook into the rotate and flip functions right before the engine does the action and run some custom script.

From here, I can get the current copy/paste blueprint from get_blueprint_entities(). For non-temporary blueprints, there are other functions that are better-suited (see https://mods.factorio.com/mod/Kux-BlueprintExtensions for examples on updating actual blueprint items/books)... After getting the blueprint entities, I am able to correctly modify the entities for both rotate and flip by iterating through them. Now we have a list of updated entities! The player only has get_blueprint_entities()... but LuaItemStack has get and set for entities (AND tiles!), and player.cursor_stack does have this info when we call get_blueprint_entities() on it. So we get the entities, update them, set them back on the cursor_stack, and we're done... right?

Well, not quite! Now that we've updated the item stack the player is "holding" (or has in their cursor, however you see it)... it seems like the engine gets confused and doesn't actually do the whole "rotate" thing on the blueprint we nicely fixed up for it, since it's no longer the same exact item stack. So, we have to do that ourselves! After calculating the bounds, we can apply a transform matrix with

Code: Select all

local function transform(position, pivot, matrix_x, matrix_y)
    local vector = position - pivot
    return {x = vector.x * matrix_x.x + vector.y * matrix_x.y, y = vector.x * matrix_y.x + vector.y * matrix_y.y}
end
and then update properties (I haven't done this quite yet, but by referencing https://wiki.factorio.com/Blueprint_string_format we can work through these one-by-one).

So now that we've fixed up entities AND done the rotate/flip manually... we can actually do the above step of setting the blueprint entities on player.cursor_stack! Change the custom input action to consume the input so we fully intercept it and bam, we've effectively replaced the vanilla rotate and flip functions!

All of this said, while this is definitely functional... this is a very brittle approach to solving the problem, and basically requires reproducing vanilla behavior in lua to make it work seamlessly. There are a handful of different ways I could see implementing support for this, but after digging through the depths of this problem lua-side and seeing both a possible solution and a fairly functional approach, I have a few thoughts:
  • If set_blueprint_entities() is an acceptable interface, calling this shouldn't invalidate doing the vanilla rotate / flip operations. Otherwise, mods have to implement this themselves, which means requiring a helper library mod and architecting it such that other mods can hook into it and add their own "entity transformations".
  • Either way, currently vanilla mirror/flip will error out if you try flipping an entity the core engine doesn't understand how to handle. This makes sense in vanilla, since entities like train stations, oil refineries, pumpjacks, and rail signals all have issues here. However, lots of mods exist with the purpose of effectively making these entities flippable (I just finished V1.0 of one myself! https://mods.factorio.com/mod/Industria ... redRecipes). A hacky solution would be to add a custom_flipped or flip_safe flag to the BlueprintEntity format (https://lua-api.factorio.com/latest/con ... rintEntity), which tells the engine that we've handled the flip ourselves and it doesn't have to error out on it.
So, if improvements to modding support for blueprints are on the roadmap, that'd be great! Otherwise, I'll happily start working on an extension-friendly mod with a solid interface for other mods to handle this whole song and dance.

Cheers!
SafTheLamb

safthelamb@gmail.com
Burner Inserter
Burner Inserter
Posts: 10
Joined: Tue Aug 22, 2023 8:45 am
Contact:

Re: Event when blueprint is rotated/flipped

Post by safthelamb@gmail.com »

PS: As an aside, before I realized that the cursor_stack does have the blueprint entities and tiles on it (I originally assumed it didn't, since serpent.block() made it seem empty), I figured out a hacktime funtimes workaround that achieves basically the exact same result, and may actually be preferable if changing cursor_stack happens to also change the original inventory/book blueprint:

Code: Select all

-- create an inventory, give it the hack blueprint item, set its entities, player.cursor_stack.set_stack()
local hack_inventory = game.create_inventory(1)
hack_inventory.insert({name="fc-hack-blueprint"})
local hack_blueprint = hack_inventory.find_item_stack("fc-hack-blueprint")
hack_blueprint.set_blueprint_entities(entities)
if player.cursor_stack ~= nil then
    player.cursor_stack.set_stack(hack_blueprint)
end

safthelamb@gmail.com
Burner Inserter
Burner Inserter
Posts: 10
Joined: Tue Aug 22, 2023 8:45 am
Contact:

Re: Event when blueprint is rotated/flipped

Post by safthelamb@gmail.com »

This almost works, but 1) I ran into too many bugs when changing function call order and details to find the golden bullet per se and 2) replacing the Rotate function isn't viable, since you can't emulate the rotate logic for items in your cursor (with Q).

So it'd still be very handy to have an improved modding support implementation for fixing up / pre-processing blueprints during transforms... may try to re-visit this, since it's almost functional and it's probably possible to get it exactly right, but it's a lot to figure out when the behavior is unintuitive since it's not a very well-defined way to interface (and/or interfere) with the game engine.

User avatar
SupplyDepoo
Filter Inserter
Filter Inserter
Posts: 286
Joined: Sat Oct 29, 2016 8:42 pm
Contact:

Re: Event when blueprint is rotated/flipped

Post by SupplyDepoo »

+1 for streamlining the blueprint APIs and making more stuff like this easy/possible!

Thanks for the detailed write-up.

Post Reply

Return to “Modding interface requests”