Heres some LUA code of a Factorio mod. Can you find some mistakes and fix it? It is…
- User
Heres some LUA code of a Factorio mod. Can you find some mistakes and fix it? It is supposed to create chests which are linked together based on an ID set in the inventories input field.
- Assistant
As an AI language model, I can't interactively troubleshoot or directly see your code. Please copy and paste the relevant LUA code here, and I'll help you identify mistakes and suggest possible improvements.
- User
require "util" -- Initialize the global table if it doesn't exist if not global then global = {} end
local GRAPHICS = "linked-6-chests/graphics" local ICONS = GRAPHICS .. "/icons" local BASE_LINKED_CHEST = GRAPHICS .. "/entity/linked-chests"
local LINKED_CHEST_BASED = "iron-chest"
-- Define global table to hold linked chest entities global.linked_chests = {}
-- Function to create a new linked chest based on the given name and ID local function new_linked_chest(name, id) local chest_id = "linked-chest-" .. id .. "-" .. name local icon = ICONS .. "/linked-chest-" .. name .. "-icon.png"
local item = util.table.deepcopy(data.raw["item"][LINKED_CHEST_BASED]) item.name = chest_id item.icon = icon item.place_result = chest_id local entity = util.table.deepcopy(data.raw["container"][LINKED_CHEST_BASED]) entity.type = "linked-container" entity.name = chest_id entity.minable.result = chest_id entity.circuit_wire_connection_point = nil entity.circuit_connector_sprites = nil entity.circuit_wire_max_distance = nil entity.inventory_size = 5000 entity.icon = icon entity.picture = { layers = { { filename = BASE_LINKED_CHEST .. "/linked-chest-" .. name .. ".png", priority = "extra-high", width = 34, height = 38, frame_count = 7, shift = util.by_pixel(0, -2), hr_version = { filename = BASE_LINKED_CHEST .. "/hr-linked-chest-" .. name .. ".png", priority = "extra-high", width = 66, height = 74, frame_count = 7, shift = util.by_pixel(0, -2), scale = 0.5 } }, { filename = BASE_LINKED_CHEST .. "/linked-chest-shadow.png", priority = "extra-high", width = 56, height = 24, repeat_count = 7, shift = util.by_pixel(12, 5), draw_as_shadow = true, hr_version = { filename = BASE_LINKED_CHEST .. "/hr-linked-chest-shadow.png", priority = "extra-high", width = 112, height = 46, repeat_count = 7, shift = util.by_pixel(12, 4.5), draw_as_shadow = true, scale = 0.5 } } }, } local recipe = { type = "recipe", name = chest_id, result = chest_id, icon = icon, icon_size = 64, enabled = true, ingredients = { {LINKED_CHEST_BASED, 1} }, } return item, entity, recipeend
-- Define a new event handler for the 'on_built_entity' and 'on_robot_built_entity' events local function on_built_linked_chest(event) local entity = event.created_entity
-- If the entity is a linked chest if entity.name:find("linked%-chest%-.+") then -- Check if there is an inventory in the chest table with the same ID local linked_chest_id = entity.linked_chest_id if linked_chest_id then local linked_chests = global.linked_chests[entity.force.name] for _, chest in pairs(linked_chests) do if chest ~= entity and chest.valid then local chest_id = chest.linked_chest_id if chest_id and chest_id == linked_chest_id then -- If a linked chest with the same ID is found, link the two chests entity.linked_chest = chest chest.linked_chest = entity break end end end end endend
script.on_event({defines.events.on_built_entity, defines.events.on_robot_built_entity}, on_built_linked_chest)
-- Check if there is an inventory in the chest table with the same ID for _, chest in pairs(linked_chests) do if chest ~= entity and chest.valid then local inv = chest.get_inventory(inventory.get_inventory(defines.inventory.chest)) if inv and inv ~= inventory then inventory.set_filter(1, inv.get_filter(1)) inventory.set_bar(inv.get_bar()) inv.set_filter(1, nil) inv.set_bar(nil) inventory.set_linked_chest(chest) break end end end
-- Add the new chest to the inventory table table.insert(linked_chests, entity)
- Assistant
I have identified some potential issues and improvements in your code. Here is the revised code with corrections:
require "util" -- Initialize the global table for linked chests if it doesn't exist if not global.linked_chests then global.linked_chests = {} end local GRAPHICS = "__linked-6-chests__/graphics" local ICONS = GRAPHICS .. "/icons" local BASE_LINKED_CHEST = GRAPHICS .. "/entity/linked-chests" local LINKED_CHEST_BASED = "iron-chest" -- Define global table to hold linked chest entities for each force for _, force in pairs(game.forces) do if not global.linked_chests[force.name] then global.linked_chests[force.name] = {} end end -- Function to create a new linked chest based on the given name and ID local function new_linked_chest(name, id) -- (existing code remains unchanged) end -- Define a new event handler for the 'on_built_entity' and 'on_robot_built_entity' events local function on_built_linked_chest(event) local entity = event.created_entity -- If the entity is a linked chest if entity.name:find("linked%-chest%-.+") then local force_name = entity.force.name -- Check if there is an inventory in the chest table with the same ID local linked_chest_id = entity.linked_chest_id if linked_chest_id then local linked_chests = global.linked_chests[force_name] for _, chest in pairs(linked_chests) do if chest ~= entity and chest.valid then local chest_id = chest.linked_chest_id if chest_id and chest_id == linked_chest_id then -- If a linked chest with the same ID is found, link the two chests entity.linked_chest = chest chest.linked_chest = entity break end end end -- Add the new chest to the inventory table table.insert(global.linked_chests[force_name], entity) end end end script.on_event({defines.events.on_built_entity, defines.events.on_robot_built_entity}, on_built_linked_chest) -- Remove the following redundant piece of code --[[ for _, chest in pairs(linked_chests) do if chest ~= entity and chest.valid then local inv = chest.get_inventory(inventory.get_inventory(defines.inventory.chest)) if inv and inv ~= inventory then inventory.set_filter(1, inv.get_filter(1)) inventory.set_bar(inv.get_bar()) inv.set_filter(1, nil) inv.set_bar(nil) inventory.set_linked_chest(chest) break end end end -- Add the new chest to the inventory table table.insert(linked_chests, entity) ]]Summary of changes:
- Add a loop to initialize the
global.linked_cheststable for each force in the game. - Replace
linked_chestswithglobal.linked_chests[force_name]throughout the code, to properly index linked chests by force name. - Move the code for adding the new chest to the inventory table within the
on_built_linked_chestfunction after checking for existing linked chests with the same ID. This ensures that the new chest is properly added to the global table. - Remove the redundant piece of code at the end of the script, as this logic has been moved to the
on_built_linked_chestfunction.
- Add a loop to initialize the
- User
I've done the recommended changes. But now I get this error
1.247 Error ModManager.cpp:1560: Failed to load mod "linked-6-chests": __linked-6-chests__/data.lua:3: attempt to index global 'global' (a nil value) stack traceback: __linked-6-chests__/data.lua:3: in main chunk - Assistant
My apologies for the confusion. The
globalvariable is not available during data phase; it's only available during runtime. To properly initialize the linked chests data, you should do that in theon_loadandon_configuration_changedevents. Here is the updated code:require "util" local GRAPHICS = "__linked-6-chests__/graphics" local ICONS = GRAPHICS .. "/icons" local BASE_LINKED_CHEST = GRAPHICS .. "/entity/linked-chests" local LINKED_CHEST_BASED = "iron-chest" -- Function to create a new linked chest based on the given name and ID local function new_linked_chest(name, id) -- (existing code remains unchanged) end -- Define a new event handler for the 'on_built_entity' and 'on_robot_built_entity' events local function on_built_linked_chest(event) -- (existing code remains unchanged) end script.on_event({defines.events.on_built_entity, defines.events.on_robot_built_entity}, on_built_linked_chest) -- Initialize the global table for linked chests for each force in the given forces local function create_linked_chests(forces) for _, force in pairs(forces) do if not global.linked_chests[force.name] then global.linked_chests[force.name] = {} end end end local function on_load() if not global.linked_chests then global.linked_chests = {} end end -- Event handler to initialize the linked chest data or update the data for new forces local function on_configuration_changed(event) if not global.linked_chests then global.linked_chests = {} end local forces = event and event.new_forces or game.forces create_linked_chests(forces) end script.on_load(on_load) script.on_configuration_changed(on_configuration_changed)Summary of changes:
- Remove the initialization of the
global.linked_cheststable at the top of the script. - Add
on_load()function to create theglobal.linked_cheststable if it doesn't exist. - Add
on_configuration_changed(event)function to initialize or update theglobal.linked_cheststable for new forces. - Register
on_load()andon_configuration_changed(event)functions with thescript.on_load()andscript.on_configuration_changed()events, respectively.
This way, the code ensures that the
global.linked_cheststable is properly initialized during the runtime phase instead of the data phase. - Remove the initialization of the