Request: Add Lua functionality to place and spawn a blueprint

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Post Reply
CharacterOverflow
Manual Inserter
Manual Inserter
Posts: 1
Joined: Wed Feb 21, 2024 2:12 pm
Contact:

Request: Add Lua functionality to place and spawn a blueprint

Post by CharacterOverflow »

Hello all, I've had a number of issues getting blueprints to 'easily' spawn into a world. By 'easily' - I mean with just one lua function call.

The current 'build_blueprint' lua function appears to represent the logic the normal player has with blueprints - the 'force' mode is just holding shift to place the blueprint with what is possible. This doesnt actually create any entities besides their ghosts

I've tried a number of ways to do this, and ended up with a solution that is really heavy-handed but works well enough. I'm also open to ideas on how to improve this process in my own code, if that's more appropriate.

What I am looking for is a lua function to fully build the specified blueprint. It can be assumed the terrain is empty in this situation, and that there are no players in the game

It needs to....
1. Place the blueprint as specified at a target location (same params as build_blueprint)
2. Spawn all entities correctly
- This is what DOESNT happen in the current build_blueprint functionality
3. Spawn all needed locomotives + schedules and logic
4. Spawn modules as needed
5. etc etc etc by the end, you should have a 100% accurate placement of the blueprint in-game

For context, I am using this as the core component of how my library (factorio-analytics) works. An empty scenario places a blueprint down, then runs the game in 'benchmark' mode. Data is extracted in this, then used elsewhere.

See file linked below to see the full scenario lua file that I use. It's basic but slow, and has been working so far for what I need.
https://github.com/CharacterOverflow/fa ... andbox.lua

If you want a direct snippet, this is my current function used to place a blueprint in-game via lua. This is, as far as I know, the only way to do this

Code: Select all

local draw_bp = function(bp)

    --build_blueprint_from_string(bp, surfaceRef, forceRef, offset)
    local s = game.get_surface('nauvis');
    local f = game.forces['bench']
    f.research_all_technologies();

    -- Creates a blueprint entitiy in-game - it's weird, but it works. This blueprint entity has the blueprint loaded we want to run.
    local bp_entity = s.create_entity { name = 'item-on-ground', position = { 0, 0 }, stack = 'blueprint' }
    bp_entity.stack.import_stack(bp)

    -- Now we call build_blueprint - this does not do *anything* like what you'd expect though. The force_build options is
    -- only there simply to hold 'shift' while the blueprint is placed, meaning the blueprint itself still does not get
    -- spawned, only the ghosts do. So, we then have much more actual work to do.
    -- #TODO - Try to talk to factorio devs and have them either make an additional function (like auto_build_blueprint) or parameter. Would eliminate most of the lua code below, and likely be a speed boost
    local bp_ghost = bp_entity.stack.build_blueprint { surface = s, force = f, position = { 0, 0 }, force_build = true }
    bp_entity.destroy()

    -- Go through and spawn the actual entities - except for ones that REQUIRE other entities, such as locomotives
    local afterSpawns = {}
    for _, entity in pairs(bp_ghost) do

        -- Should change this to go by ghost_type, if that's even a valid field.
        if (entity.ghost_name == 'locomotive' or entity.ghost_name == 'cargo-wagon' or entity.ghost_name == 'fluid-wagon') then
            table.insert(afterSpawns, entity)
        else
            if (entity ~= nil and entity.name == 'entity-ghost' and entity.ghost_type ~= nil and entity.item_requests ~= nil) then
                local items = util.table.deepcopy(entity.item_requests)
                local p, ri = entity.revive();
                if (ri ~= nil) then
                    for k, v in pairs(items) do
                        ri.get_module_inventory().insert({ name = k, count = v })
                    end
                end
            else
                -- it's a normal thing like a belt or arm - we can just 'revive' the ghost, which will place the entity with all of the correct settings from the blueprint
                entity.revive();
            end
        end

    end

    -- This is used to place all locomotives and other train objects AFTER rails have been placed
    for _, entity in pairs(afterSpawns) do
        local r, to = entity.revive();
    end

    -- Set all trains to AUTOMATIC mode (manual = false)
    for _, locomotive in pairs(game.surfaces["nauvis"].get_trains()) do
        locomotive.manual_mode = false
    end

    -- Add logistic bots to each roboport, based on input. One of the few variables, as some designs may be self-sufficient on bots
    if (BOTS ~= nil and BOTS > 0) then
        for _, roboport in pairs(game.surfaces["nauvis"].find_entities_filtered({ type = "roboport" })) do
            roboport.insert({ name = "logistic-robot", count = BOTS })
        end
    end

end

Post Reply

Return to “Modding interface requests”