[Solved] various themes: comparing tables, general code quirks, blueprint modding and how not to behave as modder(sorry)

Place to get help with not working mods / modding interface.
Lindor
Inserter
Inserter
Posts: 30
Joined: Sat Sep 28, 2019 10:54 pm
Contact:

Re: How to get a logistic chests items being fetched?

Post by Lindor »

eradicator wrote:
Wed Oct 02, 2019 10:11 pm
Making blueprints should not affect how the factory works. But that's more of an ugly quirk than a bug if you want to do it like that.
It affects it only for a max of 29 ticks. But i trust your advice more. i'll swap them back.
eradicator wrote:
Wed Oct 02, 2019 10:11 pm
Please state the nature of the medical emergency obvious reasons. I don't see any. Reopening a gui in the same tick it was closed is unnoticible™ for the player.
Well any mod that uses player.opened_self would break after my force-open.
eradicator wrote:
Wed Oct 02, 2019 10:11 pm
I thought the whole point of the blueprint hacking was to never allow them to be in a blueprint in the first place. So why worry about craftability? Are you unaware of the fact that you can change the type of the chest *inside* the blueprint (via get_blueprint_entities, set_blueprint_entities)? And then there's also "placeable_by" if for some reason you still need that.
In this case i once was aware of that. What i said is that i need to swap chests, regardless of it being done before the blueprint was taken or after. I thought you mean that i can leave the provider chests in but setup a function on an event to update my global table everytime a player creates ghosts with that blueprint. This was a response to:
eradicator wrote:
Wed Oct 02, 2019 7:19 pm
With the new event.mapping you don't even need to swap the chests, you can just fetch the data from your global table.
.
eradicator wrote:
Wed Oct 02, 2019 10:11 pm
And reassigning event handlers inside events will only affect the *next* time the event is raised anyway.
I don't understand what you try to say :? Which one of the events do you mean?
eradicator wrote:
Wed Oct 02, 2019 10:11 pm
By wanting to manipulate blueprints while the player makes them you've chosen a minefield as your first modding environment. You have to do a lot of learning and testing to get it right. And you'll have to do most of it on your own. (Also what is "setup-q-setup-confirm" supposed to mean? Did you misunderstand "re-open the gui" to be a player action?)
Yes, more and more i realise that. With "setup-q-setup-confirm" i mean the player drags the blueprint area calling on_player_setup_blueprint but is not happy about it and does not confirm, instead closing and draging a new blueprint area, calling on_player_setup_blueprint a second time before on_player_configured.blueprint. So not the "GUI-re-opening" but the "re-draging" is what i'm concerned about.

Edit: Oh i just realised i completely misunderstood the descrition of player.open_self. It's supposed to return wether the player opened it's inventory grid, not that a player opened something by itself. But would it affect on_GUI_opened twice?

Lindor
Inserter
Inserter
Posts: 30
Joined: Sat Sep 28, 2019 10:54 pm
Contact:

Re: How to get a logistic chests items being fetched?

Post by Lindor »

Don't worry anymore, i finished the mod and so far at least in singleplayer everything is working as i hoped. Again a big thank you for making this mod possible. As i said, i thanked you in the mod description, eradicator (https://mods.factorio.com/mod/logistic-chest-overflow). I've learned some lessons, if i don't know what to do about a problem, i'll ask for help instead of stating it a bug and i'll only ask for help if i really need help instead of everytime there's a problem i can't solve in a few hours. In case anybody wants to know without downloading the mod, this is my final code for version 0.1.0:

Code: Select all

--setting up the globals. We need all modded chests and their request slots.
script.on_init(function()
    if global.reqtable == nil then
        global.reqtable = {}
    end
    global.chests = game.surfaces.find_entities_filtered{type = "logistic-container", name = {"logistic-chest-overflow", "logistic-chest-overflow-provider"}} or {}
end)


--fast replace a chest with another and delete the old one from global.chests We need to do this manually because create_entity won't call on_script_raised_destroy.
function switchchests(fromchest, toname, frompos, key)
    if fromchest.valid == true then
        global.chests[key] = nil
        return fromchest.surface.create_entity{name=toname, position=frompos, force=fromchest.force, fast_replace=true, raise_built=true, player=nil, spill=false}
    end
end


-- the main logic
function main(event)
    --every 30 ticks which means twice a second
    if event.tick % 30 == 0 then
        --check all chests
		if global.chests ~= nil then
            for k, chest in pairs(global.chests) do
                if chest.valid == true then
                    if chest.to_be_deconstructed(chest.force) == false then
                        local pos = {chest.position.x, chest.position.y}
                        local i = 0
                        local chestID = chest.unit_number
                        if chest.name == "logistic-chest-overflow" then
                            for slot = 1, 12 do
                                if chest.get_request_slot(slot) ~= nil then
                                    --has the request been satisfied?
                                    if chest.get_request_slot(slot).count <= chest.get_item_count(chest.get_request_slot(slot).name) then
                                        i = 1
                                        break
                                    end
                                end
                            end
                        end
                        if chest.name == "logistic-chest-overflow-provider" then
                            for slot = 1, 12 do
                                if global.reqtable[chestID] ~= nil then
                                    if global.reqtable[chestID][slot] ~= nil then
                                        --has the request been satisfied?
                                        if global.reqtable[chestID][slot][2] <= chest.get_item_count(global.reqtable[chestID][slot][1]) then
                                            i = 1
                                            break
                                        end
                                    end
                                end
                            end
                        end
                        --if it has been satisfied, switch it to a provider chest and save the request with unit_number or end
                        if i == 1 then
                            if chest.name == "logistic-chest-overflow" then
                                local request = {}
                                for slot = 1, 12 do
                                    if chest.get_request_slot(slot) ~= nil then
                                        request[slot] = {chest.get_request_slot(slot).name, chest.get_request_slot(slot).count}
                                    end
                                end
                                local newchest = switchchests(chest, "logistic-chest-overflow-provider", pos, k)
                                global.reqtable[newchest.unit_number] = request
                            end
                        end
                        --if not, switch it back and set the saved slots again or end
                        if i == 0 then
                            if chest.name == "logistic-chest-overflow-provider" then
                                local newchest = switchchests(chest, "logistic-chest-overflow", pos, k)
                                for slot = 1, 12 do
                                    if global.reqtable[chestID] ~= nil then
                                        if global.reqtable[chestID][slot] ~= nil then
                                            newchest.set_request_slot({name=global.reqtable[chestID][slot][1], count=global.reqtable[chestID][slot][2]}, slot)
                                        end
                                    end
                                end
                                --delete the saved requests to prevent reqtable from getting massive
                                global.reqtable[chestID] = nil
                            end
                        end
                    end
                end
            end
        end
    end
end

script.on_event({defines.events.on_tick}, main)


--check for new chests
function built(event)
    local entity = event.entity or event.created_entity
    if (entity.name == "logistic-chest-overflow") or (entity.name == "logistic-chest-overflow-provider") then
        table.insert(global.chests, entity)
    end
end
	
script.on_event(defines.events.on_built_entity, built)
script.on_event(defines.events.on_robot_built_entity, built)
script.on_event(defines.events.script_raised_built, built)


--check for deleted chests
function mined(event)
    local entity = event.entity
    if (entity.name == "logistic-chest-overflow") or (entity.name == "logistic-chest-overflow-provider") then
        for key, ent in pairs(global.chests) do
            if ent == entity then
                table.remove(global.chests, key)
                break
            end
        end
    end
    if entity.name == "logistic-chest-overflow-provider" then
        table.remove(global.reqtable, entity.unit_number)
    end
end

script.on_event(defines.events.on_player_mined_entity, mined)
script.on_event(defines.events.on_robot_mined_entity, mined)
script.on_event(defines.events.script_raised_destroy, mined)


--check for new created blueprints
function blueprint_set(event)
    local blueprint = game.players[event.player_index].blueprint_to_setup
    if not blueprint or not blueprint.valid_for_read then
        blueprint = game.players[event.player_index].cursor_stack
    end
    local ents = blueprint.get_blueprint_entities()
    local cursedmapping = event.mapping.get()
    local cleanmapping = {}
    for key, entity in pairs(ents) do
        if not entity.name == "logistic-chest-overflow-provider" then
            table.remove(ents, key)
        end
        if entity.name == "logistic-chest-overflow-provider" then
            --here comes the tricky part. get_blueprint_entities does not contain class LuaEntity but blueprint entity instead. This class is not listed in lua-api.factorio.com. To get the inner structure of the mentioned entity specific fields nothing else helps than abusing the game.surfaces[].print command and testing.
            cleanmapping[entity] = cursedmapping[entity.entity_number].unit_number
            entity.name = "logistic-chest-overflow"
            local b = {}
            local c = 1
            local d = {index = nil, name = nil, count = nil}
            for slot = 1, 12 do
                if global.reqtable[cleanmapping[entity]] ~= nil then
                    if global.reqtable[cleanmapping[entity]][slot] ~= nil then
                        d["index"] = slot
                        d["name"] = global.reqtable[cleanmapping[entity]][slot][1]
                        d["count"] = global.reqtable[cleanmapping[entity]][slot][2]
                        table.insert(b, c, d)
                        c=c+1
                    end
                end
            end
            entity["request_filters"] = b
        end
    end
   blueprint.set_blueprint_entities(ents)
end

script.on_event(defines.events.on_player_setup_blueprint, blueprint_set)
Last edited by Lindor on Sat Oct 05, 2019 9:14 am, edited 1 time in total.

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

Re: [Solved] various themes: comparing tables, general code quirks, blueprint modding and how not to behave as modder(so

Post by eradicator »

Glad i could help. Grats on finishing your mod :). A very quick look at least doesn't reveal any totally obvious bugs anymore.
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.

Post Reply

Return to “Modding help”