local EXPORTER_NAME = "signal-exporter" local EXPORT_INTERVAL = 1800 -- Ticks between file writes (1800 = 30s at 60 UPS) local function init_global() global.exporters = global.exporters or {} global.open_guis = global.open_guis or {} end script.on_init(init_global) script.on_configuration_changed(init_global) local function export_combinator(unit_number, data) local entity = data.entity if not (entity and entity.valid) then global.exporters[unit_number] = nil return end local signals = { game_tick = game.tick, circuit_network = { red = {}, green = {} }, logistic_network = {} } local wires = { [defines.wire_type.red] = "red", [defines.wire_type.green] = "green" } for wire_type, color in pairs(wires) do local network = entity.get_circuit_network(wire_type) if network and network.signals then for _, signal in ipairs(network.signals) do local name = signal.signal.name if name then signals.circuit_network[color][name] = (signals.circuit_network[color][name] or 0) + signal.count end end end end local logistic_network = entity.surface.find_logistic_network_by_position(entity.position, entity.force) if logistic_network then local contents = logistic_network.get_contents() for name, count in pairs(contents) do signals.logistic_network[name] = count end end local json_string = game.table_to_json(signals) game.write_file("signal_export/" .. data.name .. ".json", json_string, false) end local function on_created(event) local entity = event.created_entity or event.entity or event.destination if not (entity and entity.valid) then return end if entity.name == EXPORTER_NAME then global.exporters[entity.unit_number] = { entity = entity, name = "combinator_" .. tostring(entity.unit_number) } end end local function on_destroyed(event) local entity = event.entity if not (entity and entity.valid) then return end if entity.name == EXPORTER_NAME then global.exporters[entity.unit_number] = nil end end local build_events = { defines.events.on_built_entity, defines.events.on_robot_built_entity, defines.events.script_raised_built, defines.events.script_raised_revive } for _, e in ipairs(build_events) do script.on_event(e, on_created) end local destroy_events = { defines.events.on_player_mined_entity, defines.events.on_robot_mined_entity, defines.events.on_entity_died, defines.events.script_raised_destroy } for _, e in ipairs(destroy_events) do script.on_event(e, on_destroyed) end script.on_nth_tick(EXPORT_INTERVAL, function() for unit_number, data in pairs(global.exporters) do export_combinator(unit_number, data) end end) script.on_event(defines.events.on_gui_opened, function(event) local entity = event.entity if entity and entity.valid and entity.name == EXPORTER_NAME then local player = game.players[event.player_index] local data = global.exporters[entity.unit_number] if not data then return end local screen = player.gui.screen if screen["signal_exporter_gui"] then screen["signal_exporter_gui"].destroy() end local frame = screen.add{type = "frame", name = "signal_exporter_gui", caption = "Configure Signal Exporter", direction = "vertical"} frame.force_auto_center() local name_flow = frame.add{type = "flow", name = "name_flow", direction = "horizontal"} name_flow.style.vertical_align = "center" name_flow.style.bottom_margin = 8 name_flow.add{type = "label", caption = "Combinator Name: "} name_flow.add{type = "textfield", name = "exporter_name_input", text = data.name} local button_flow = frame.add{type = "flow", name = "button_flow", direction = "horizontal"} button_flow.add{type = "button", name = "exporter_save_button", caption = "Save & Close"} button_flow.add{type = "button", name = "exporter_refresh_button", caption = "Export Now"} player.opened = frame global.open_guis[player.index] = entity.unit_number end end) script.on_event(defines.events.on_gui_click, function(event) local element = event.element if element.name == "exporter_save_button" or element.name == "exporter_refresh_button" then local player = game.players[event.player_index] local unit_number = global.open_guis[player.index] if unit_number and global.exporters[unit_number] then local frame = player.gui.screen["signal_exporter_gui"] if frame then local new_name = frame.name_flow.exporter_name_input.text global.exporters[unit_number].name = new_name end if element.name == "exporter_refresh_button" then export_combinator(unit_number, global.exporters[unit_number]) player.print("Data manually exported to signals_" .. global.exporters[unit_number].name .. ".json") end end if element.name == "exporter_save_button" then if player.gui.screen["signal_exporter_gui"] then player.gui.screen["signal_exporter_gui"].destroy() end global.open_guis[player.index] = nil end end end) script.on_event(defines.events.on_gui_closed, function(event) if event.element and event.element.name == "signal_exporter_gui" then event.element.destroy() global.open_guis[event.player_index] = nil end end) local function export_item_names_csv(event) local player = game.players[event.player_index] local csv_lines = { '"item_key","localised_name"' } local function escape_csv_field(value) if value == nil then return "" end return string.gsub(tostring(value), '"', '""') end for _, item_prototype in pairs(game.item_prototypes) do local key = item_prototype.name local resolved_name = player.localise(item_prototype.localised_name) local escaped_key = escape_csv_field(key) local escaped_name = escape_csv_field(resolved_name) table.insert(csv_lines, '"' .. escaped_key .. '","' .. escaped_name .. '"') end local csv_content = table.concat(csv_lines, "\n") game.write_file("item_names.csv", csv_content, false, player.index) player.print("Export complete. File saved to 'script-output/item_names.csv'.") end commands.add_command( "export-item-names", "Exports the internal name (key) and localised name for all game items to a CSV file.", export_item_names_csv )