Enhance peripheral handling: implement caching for peripheral wraps to improve performance

This commit is contained in:
MayaTheShy
2026-03-22 01:36:45 -04:00
parent a5e6be7f4b
commit 4637275529

View File

@@ -749,6 +749,28 @@ local function invalidatePeripheralCaches()
cachedFurnaces = nil
end
-- Peripheral handle cache (avoids re-creating proxy tables on every call)
-- Handles are cleared on peripheral_detach events and during full scans.
local wrapCache = {}
local function wrapCached(name)
local handle = wrapCache[name]
if handle then return handle end
handle = peripheral.wrap(name)
if handle then
wrapCache[name] = handle
end
return handle
end
local function invalidateWrapCache(name)
if name then
wrapCache[name] = nil
else
wrapCache = {}
end
end
local function getChests()
local now = os.clock()
if cachedChests and (now - cachedChestsTime) < PERIPHERAL_CACHE_TTL then
@@ -787,7 +809,7 @@ local function refreshFurnaceStatus()
local furnaces = getFurnaces()
local status = {}
for _, fname in ipairs(furnaces) do
local furnace = peripheral.wrap(fname)
local furnace = wrapCached(fname)
if furnace then
local contents = furnace.list()
local entry = {
@@ -805,7 +827,7 @@ local function refreshFurnaceStatus()
end
local function scanInventory(deviceName)
local inv = peripheral.wrap(deviceName)
local inv = wrapCached(deviceName)
if not inv then return {} end
local result = {}
for slot, item in pairs(inv.list()) do
@@ -823,6 +845,9 @@ end
local function refreshCache(onProgress)
activity.scanning = true
-- Clear handle cache so we pick up any changes
invalidateWrapCache()
-- Single pass over peripherals: classify into chests and furnaces
local chests = {}
local furnaces = {}
@@ -851,7 +876,7 @@ local function refreshCache(onProgress)
for ci, chest in ipairs(chests) do
if onProgress then onProgress(ci, #chests, chest) end
local inv = peripheral.wrap(chest)
local inv = wrapCached(chest)
if inv then
totalSlots = totalSlots + inv.size()
local contents = inv.list()
@@ -896,8 +921,8 @@ local function refreshCache(onProgress)
cache.usedSlots = usedSlots
cache.freeSlots = totalSlots - usedSlots
cache.usedRatio = totalSlots > 0 and (usedSlots / totalSlots) or 0
cache.dropperOk = peripheral.wrap(DROPPER_NAME) ~= nil
cache.barrelOk = peripheral.wrap(BARREL_NAME) ~= nil
cache.dropperOk = peripheral.isPresent(DROPPER_NAME)
cache.barrelOk = peripheral.isPresent(BARREL_NAME)
-- Discover all droppers on the network (for location-based dispensing)
-- Use name-based matching as peripheral.getType() may return "inventory"
@@ -1641,7 +1666,7 @@ local function craftItem(recipeIdx)
if cache.catalogue[itemName] then
for _, source in ipairs(cache.catalogue[itemName]) do
local chest = peripheral.wrap(source.chest)
local chest = wrapCached(source.chest)
if chest then
for slot, slotItem in pairs(chest.list()) do
local key = source.chest .. ":" .. slot
@@ -1737,7 +1762,7 @@ local function craftItem(recipeIdx)
for _, r in ipairs(result.results) do
-- Find which chest likely received it
for _, ch in ipairs(chests) do
local chest = peripheral.wrap(ch)
local chest = wrapCached(ch)
if chest then
for slot, slotItem in pairs(chest.list()) do
if slotItem.name == r.name then
@@ -2060,7 +2085,7 @@ local function drawSmelterDashboard()
-- ===== Available Crafting Recipes =====
-- Turtle status on tab row
local turtleOk = craftTurtleName and peripheral.wrap(craftTurtleName) ~= nil
local turtleOk = craftTurtleName and peripheral.isPresent(craftTurtleName)
local tLabel = turtleOk and " Turtle OK " or " No Turtle "
local tBg = turtleOk and colors.lime or colors.red
local tFg = turtleOk and colors.black or colors.white
@@ -2272,7 +2297,7 @@ end
local function sortBarrel(barrelOverride)
local barrelTarget = (barrelOverride and barrelOverride ~= "") and barrelOverride or BARREL_NAME
local barrel = peripheral.wrap(barrelTarget)
local barrel = wrapCached(barrelTarget)
if not barrel then return end
local contents = barrel.list()
@@ -2344,7 +2369,7 @@ local function autoSmelt()
local emptyInputFurnaces = {} -- collected during steps 1-3, filled in step 5
for _, fname in ipairs(furnaces) do
local furnace = peripheral.wrap(fname)
local furnace = wrapCached(fname)
if furnace then
local contents = furnace.list()
@@ -2420,7 +2445,7 @@ local function autoSmelt()
for _, fuel in ipairs(FUEL_LIST) do
if catalogue[fuel.name] then
for _, source in ipairs(catalogue[fuel.name]) do
local chest = peripheral.wrap(source.chest)
local chest = wrapCached(source.chest)
if chest then
for slot, slotItem in pairs(chest.list()) do
if slotItem.name == fuel.name then
@@ -2505,7 +2530,7 @@ local function autoSmelt()
local loaded = false
for _, source in ipairs(catalogue[itemName]) do
local chest = peripheral.wrap(source.chest)
local chest = wrapCached(source.chest)
if chest then
for slot, slotItem in pairs(chest.list()) do
if slotItem.name == itemName then
@@ -2556,7 +2581,7 @@ local function defragInventory()
-- Build a map: itemName -> list of { chest, slot, count, maxCount }
local itemSlots = {}
for _, chestName in ipairs(chests) do
local inv = peripheral.wrap(chestName)
local inv = wrapCached(chestName)
if inv then
local contents = inv.list()
local detail_cache = {}
@@ -2603,7 +2628,7 @@ local function defragInventory()
else
local space = recv.max - recv.count
local toMove = math.min(donor.count, space)
local donorInv = peripheral.wrap(donor.chest)
local donorInv = wrapCached(donor.chest)
if donorInv then
local n = donorInv.pushItems(recv.chest, donor.slot, toMove, recv.slot)
if n and n > 0 then
@@ -2636,7 +2661,7 @@ local function autoCompost()
local didWork = false
-- 1) Pull bone meal from hopper back to chests
local hopper = peripheral.wrap(COMPOST_HOPPER)
local hopper = wrapCached(COMPOST_HOPPER)
if hopper then
local contents = hopper.list()
if contents then
@@ -2655,7 +2680,7 @@ local function autoCompost()
end
-- 2) Feed compostable items into dropper
local dropper = peripheral.wrap(COMPOST_DROPPER)
local dropper = wrapCached(COMPOST_DROPPER)
if not dropper then return didWork end
-- Check how much item capacity the dropper has (slots * 64 - current items)
@@ -2689,7 +2714,7 @@ local function autoCompost()
local toFeed = math.min(available, dropperFreeItems)
local fed = 0
for _, source in ipairs(catalogue[itemName]) do
local chest = peripheral.wrap(source.chest)
local chest = wrapCached(source.chest)
if chest then
for slot, slotItem in pairs(chest.list()) do
if slotItem.name == itemName then
@@ -2766,7 +2791,7 @@ local function orderItem(itemName, amount, dropperOverride)
return false
end
local dropper = peripheral.wrap(dropperTarget)
local dropper = wrapCached(dropperTarget)
if not dropper then
statusMessage = "Dropper offline: " .. dropperTarget
statusColor = colors.red
@@ -2778,7 +2803,7 @@ local function orderItem(itemName, amount, dropperOverride)
local remaining = amount
for _, entry in ipairs(catalogue[itemName]) do
local chest = peripheral.wrap(entry.chest)
local chest = wrapCached(entry.chest)
if chest then
for slot, slotItem in pairs(chest.list()) do
if slotItem.name == itemName then
@@ -3011,7 +3036,7 @@ local function broadcastState()
disabledRecipes = disabledRecipes,
smeltable = SMELTABLE,
craftable = CRAFTABLE,
craftTurtleOk = craftTurtleName and peripheral.wrap(craftTurtleName) ~= nil,
craftTurtleOk = craftTurtleName and peripheral.isPresent(craftTurtleName),
}
networkModem.transmit(BROADCAST_CHANNEL, ORDER_CHANNEL, state)
end
@@ -3026,13 +3051,13 @@ local function main()
print("=================================")
print("")
if peripheral.wrap(DROPPER_NAME) then
if peripheral.isPresent(DROPPER_NAME) then
print("[OK] Dropper: " .. DROPPER_NAME)
else
print("[WARN] Dropper not found: " .. DROPPER_NAME)
end
if peripheral.wrap(BARREL_NAME) then
if peripheral.isPresent(BARREL_NAME) then
print("[OK] Barrel: " .. BARREL_NAME)
else
print("[WARN] Barrel not found: " .. BARREL_NAME)
@@ -3093,12 +3118,12 @@ local function main()
print(string.format("[INIT] %d/%d recipes enabled", enabledCount, totalRecipeCount))
-- Detect compost peripherals
if peripheral.wrap(COMPOST_DROPPER) then
if peripheral.isPresent(COMPOST_DROPPER) then
print("[OK] Compost dropper: " .. COMPOST_DROPPER)
else
print("[WARN] Compost dropper not found: " .. COMPOST_DROPPER)
end
if peripheral.wrap(COMPOST_HOPPER) then
if peripheral.isPresent(COMPOST_HOPPER) then
print("[OK] Compost hopper: " .. COMPOST_HOPPER)
else
print("[WARN] Compost hopper not found: " .. COMPOST_HOPPER)