local rv = {} --[[ local function tailcall() print("called") if true then print("calling") return tailcall() end end tailcall() ]] local fs = require("filesystem") local function trim(str) return string.gsub(str,"^[%s]*", ""):gsub("[%s]*$", "") end function rv:getRecipes() if not fs:fileExists("recipes.txt") then return {} end local recipeText = fs:readAllText("recipes.txt") local splits = string.split(recipeText, ";") local allRecipes = {} -- outputInternalName : {resultCount:int, slots:{{possible options.....},nil,nil,....}} for _, value in ipairs(splits) do local trimmed = trim(value) if #(trimmed) > 0 then --print("trimmed:", ">>"..trimmed.."<<") local resCnt, resItem, ingredients = trimmed:match("^(%d*) (%S+) = ([^;]*)$") assert(ingredients, ("failed to match ingredients for line: >>%s<< from >>%s<<"):format(trimmed, value)) ingredients = trim(ingredients) --print(("Can craft %sx %s using ingredients %s"):format(resCnt, resItem, ingredients)) assert(allRecipes[resItem] == nil, ("more than one recipe defined for %s"):format(resItem)) local slotTable = {} for slotIdx, optionsString in ipairs(ingredients:gsub("%s",""):split(",")) do if optionsString == "nil" then slotTable[slotIdx] = nil else local slotOptions = {} for _, option in ipairs(optionsString:split("|")) do assert((option ~= nil) and (option ~= "nil"), "somehow option was nil or nilstring") assert(option:find(":"), string.format("slotoptions '%s' does not contain :",option)) table.insert(slotOptions, option) end slotTable[slotIdx] = slotOptions end end allRecipes[resItem] = { resultCount = assert(tonumber(resCnt), ("couldnt parse number '%s'"):format(resCnt)), slots = slotTable, resultItem = resItem } end end return allRecipes end function rv:serializeSingleRecipe(recipe) local slots = {} for i = 1, 9 do if recipe.slots[i] == nil or #(recipe.slots[i]) == 0 then slots[i] = "nil" else slots[i] = table.concat(recipe.slots[i], "|") end end return string.format("%d %s = %s", recipe.resultCount, recipe.resultItem, table.concat(slots,","))..";" end local function serializeRecipes(recipeTable) local newText = "" for k,v in pairs(recipeTable) do assert(k == v.resultItem, "somehow resultItem doesnt match the key") newText = newText .. rv:serializeSingleRecipe(v) .. "\n" end return newText end function rv:addNewRecipe(newRecipeTable) local cnt = assert(newRecipeTable.resultCount, "resultCount not set") local slots = assert(newRecipeTable.slots, "slots not set") local resultItem = assert(newRecipeTable.resultItem, "resultItem not set") local currRecipes = rv:getRecipes() assert(currRecipes[resultItem] == nil, ("recipe for %s has already been defined"):format(resultItem)) currRecipes[resultItem] = { resultCount = cnt, slots = slots, resultItem = resultItem } fs:writeAllText("recipes.txt", serializeRecipes(currRecipes)) end return rv