diff --git a/init.lua b/init.lua index 64d48e9..48673b5 100644 --- a/init.lua +++ b/init.lua @@ -76,9 +76,9 @@ local function shallow_copy(t) return out end --- Locale-Resolver: akzeptiert entity_handle (bw-compat) ODER table --- {sources={...}, sink=...}. Returns immer Form-2 mit validierten --- Feldern. Loud-Error bei kaputter Form-2. +-- Locale resolver: accepts entity_handle (bw-compat) OR table +-- {sources={...}, sink=...}. Always returns Form-2 with validated +-- fields. Loud-error on malformed Form-2. local function resolve_locale(locale, fn_name) -- Form 2: explicit table if type(locale) == "table" and locale.sources ~= nil then @@ -92,7 +92,27 @@ local function resolve_locale(locale, fn_name) "crafting.%s: locale.sink must not be nil", fn_name), 3) end - return locale + -- De-duplicate sources by identity, preserving first-occurrence order. + -- A caller building sources programmatically (e.g. {workbench_buffer, + -- player_backpack} where both alias the same entity) should not have + -- count_by_template double-count nor craft silent-fail. + local seen, deduped = {}, {} + for _, s in ipairs(locale.sources) do + if not seen[s] then + seen[s] = true + deduped[#deduped + 1] = s + end + end + return { sources = deduped, sink = locale.sink } + end + -- Form 2 malformed: a table that's not Form-2 (no sources key) is almost + -- certainly a caller typo. Loud-error explicitly instead of silently + -- falling through to the Form-1 bw-compat path (which would then crash + -- deep inside inventory-list with an opaque error). + if type(locale) == "table" then + error(string.format( + "crafting.%s: locale table must contain 'sources' field", + fn_name), 3) end -- Form 1 (bw-compat): bare entity_handle if locale == nil then