<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.mineinabyss.com/w/Module:Crafting_usage/history?feed=atom</id>
	<title>Module:Crafting usage - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.mineinabyss.com/w/Module:Crafting_usage/history?feed=atom"/>
	<link rel="alternate" type="text/html" href="https://wiki.mineinabyss.com/w/Module:Crafting_usage/history"/>
	<updated>2026-04-08T23:37:37Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://wiki.mineinabyss.com/index.php?title=Module:Crafting_usage&amp;diff=629&amp;oldid=prev</id>
		<title>Scyu: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://wiki.mineinabyss.com/index.php?title=Module:Crafting_usage&amp;diff=629&amp;oldid=prev"/>
		<updated>2024-10-11T14:43:53Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 14:43, 11 October 2024&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Scyu</name></author>
	</entry>
	<entry>
		<id>https://wiki.mineinabyss.com/index.php?title=Module:Crafting_usage&amp;diff=628&amp;oldid=prev</id>
		<title>minecraft&gt;ThermoF: Undo revision 2706568 by ThermoF (talk)</title>
		<link rel="alternate" type="text/html" href="https://wiki.mineinabyss.com/index.php?title=Module:Crafting_usage&amp;diff=628&amp;oldid=prev"/>
		<updated>2024-10-03T14:51:20Z</updated>

		<summary type="html">&lt;p&gt;Undo revision &lt;a href=&quot;/w/Special:Diff/2706568&quot; title=&quot;Special:Diff/2706568&quot;&gt;2706568&lt;/a&gt; by &lt;a href=&quot;/w/Special:Contributions/ThermoF&quot; title=&quot;Special:Contributions/ThermoF&quot;&gt;ThermoF&lt;/a&gt; (&lt;a href=&quot;/w/User_talk:ThermoF/edit?redlink=1&quot; class=&quot;new&quot; title=&quot;User talk:ThermoF (page does not exist)&quot;&gt;talk&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[&lt;br /&gt;
Test page listing important test cases, used to preview before saving any changes.&lt;br /&gt;
Template:Crafting_usage/test_page&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
local titleText = mw.title.getCurrentTitle().text&lt;br /&gt;
&lt;br /&gt;
local i18n = {&lt;br /&gt;
	emptyCategory = &amp;#039;Empty crafting usage&amp;#039;,&lt;br /&gt;
	moduleCrafting = [[Module:Crafting]],&lt;br /&gt;
	moduleSlot = [[Module:Inventory slot]],&lt;br /&gt;
	moduleAliases = [[Module:Inventory slot/Aliases]],&lt;br /&gt;
	moduleText = [[Module:Text]],&lt;br /&gt;
	templateCrafting = &amp;#039;Crafting&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
p.i18n = i18n&lt;br /&gt;
&lt;br /&gt;
local text = require(i18n.moduleText)&lt;br /&gt;
local slot = require(i18n.moduleSlot)&lt;br /&gt;
local aliases = require(i18n.moduleAliases)&lt;br /&gt;
local crafting = require(i18n.moduleCrafting)&lt;br /&gt;
&lt;br /&gt;
local function filterFrames(craftingArgs, pinnedItems)&lt;br /&gt;
	-- Create a lookup table to easily determine if a string is a member of pinned items.&lt;br /&gt;
	local pinnedItemsLookup = {}&lt;br /&gt;
	for _, entry in pairs(pinnedItems) do&lt;br /&gt;
		pinnedItemsLookup[entry] = true	&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Find any frames in this string that need to be pinned and pin them.&lt;br /&gt;
	local outputPinnedFrameCount = {}&lt;br /&gt;
	local shouldPinOutput = false&lt;br /&gt;
	local function pinFrames(inputString, restrictToMatching, isOutput)&lt;br /&gt;
		if not inputString then return nil end&lt;br /&gt;
		isOutput = isOutput or false&lt;br /&gt;
		&lt;br /&gt;
		local pinFrames = {} -- Only frames that are pinned&lt;br /&gt;
		local pinnedFrameCount = 0&lt;br /&gt;
		local pinnedFramesIndex = {}&lt;br /&gt;
		local allFrames = {} -- All input frames&lt;br /&gt;
		local allFrameCount = 0&lt;br /&gt;
		local frameCount = 0 -- Count how many expanded frames we are in our iteration. Used for restricting output frames to match input frames&lt;br /&gt;
		&lt;br /&gt;
		for frameStr in string.gmatch(inputString, &amp;quot;[^;]+&amp;quot;) do&lt;br /&gt;
			local shouldPin = false&lt;br /&gt;
			frameStr = mw.text.trim(frameStr)&lt;br /&gt;
			local originalFrameString = frameStr&lt;br /&gt;
			local frameObj = slot.makeFrame(frameStr, &amp;#039;&amp;#039;)&lt;br /&gt;
			local name = (frameObj.name:gsub(&amp;quot;[{}]&amp;quot;, &amp;quot;&amp;quot;)) -- If this name is a subframe, remove the braces for alias testing.&lt;br /&gt;
			local subframe = (frameObj.name:find(&amp;quot;[{}]&amp;quot;) ~= nil) -- If the current frame is a subframe, don&amp;#039;t advance the frame count for aliases&lt;br /&gt;
			local expandedAlias = aliases[name]&lt;br /&gt;
			local isAlias = (expandedAlias and expandedAlias[1]) ~= nil&lt;br /&gt;
			local isDesiredItem = (pinnedItemsLookup[name] ~= nil) -- If this item is present in our list of items to pin&lt;br /&gt;
			&lt;br /&gt;
			-- Even if we have an exactly matching alias input, we have to step through each frame to log it as pinnable.&lt;br /&gt;
			if isAlias == true and isDesiredItem then&lt;br /&gt;
				shouldPin = true -- Set this frame as adding to the list of pinned frames&lt;br /&gt;
				if not subframe then&lt;br /&gt;
					for _,_ in pairs(expandedAlias) do&lt;br /&gt;
						frameCount = frameCount + 1&lt;br /&gt;
						pinnedFramesIndex[frameCount] = true&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					frameCount = frameCount + 1&lt;br /&gt;
					pinnedFramesIndex[frameCount] = true&lt;br /&gt;
				end&lt;br /&gt;
			elseif isAlias == false or subframe == true then&lt;br /&gt;
				frameCount = frameCount + 1&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			if isAlias -- If this is an alias&lt;br /&gt;
			and not isDesiredItem -- and we don&amp;#039;t want to keep the alias as is&lt;br /&gt;
			and (not isOutput or (isOutput and restrictToMatching)) then -- and we are either not output, or we are output that needs to be restricted.&lt;br /&gt;
				local replacementString = {}&lt;br /&gt;
				for _,candidate in pairs(expandedAlias) do -- Find all pinned items that are part of this alias&lt;br /&gt;
					if not subframe then -- Subframes only actually count as one frame&lt;br /&gt;
						frameCount = frameCount + 1&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					candidate = candidate.name or candidate -- Sometimes alias returns a table of tables&lt;br /&gt;
					if pinnedItemsLookup[candidate] or (restrictToMatching and outputPinnedFrameCount[frameCount]) then&lt;br /&gt;
						local candidateOut = candidate&lt;br /&gt;
						if frameObj.num then&lt;br /&gt;
							candidateOut = candidateOut..&amp;#039;,&amp;#039;..frameObj.num	&lt;br /&gt;
						end&lt;br /&gt;
						table.insert(replacementString, candidateOut)&lt;br /&gt;
						pinnedFramesIndex[frameCount] = true -- When we find a good entry, store the number for use by Output&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				if #replacementString &amp;gt; 0 then -- If this alias doesn&amp;#039;t have any pinned items in it, leave it alone.&lt;br /&gt;
					if name:find(&amp;quot;^&amp;quot; .. slot.i18n.prefixes.any .. &amp;quot; &amp;quot;) then&lt;br /&gt;
						-- Simple in place randomization&lt;br /&gt;
						for i = #replacementString, 2, -1 do&lt;br /&gt;
							local j = math.random(i)&lt;br /&gt;
							replacementString[i], replacementString[j] = replacementString[j], replacementString[i]&lt;br /&gt;
						end&lt;br /&gt;
					else -- If we modify anything that isn&amp;#039;t an &amp;quot;Any&amp;quot; alias, force pin the output.&lt;br /&gt;
						shouldPinOutput = true&lt;br /&gt;
					end&lt;br /&gt;
					replacementString = table.concat(replacementString, &amp;#039;;&amp;#039;)&lt;br /&gt;
					-- The gsub is to put a % in front of every non alphanumeric character in name, this escapes the name so special characters don&amp;#039;t act as a pattern match.&lt;br /&gt;
					local findString = &amp;#039;(&amp;#039;..name:gsub(&amp;quot;(%W)&amp;quot;, &amp;quot;%%%1&amp;quot;)..&amp;#039;,?%d*)&amp;#039; -- Also capture the quantity, since the replacement string has the quantity attached.&lt;br /&gt;
					frameStr = frameStr:gsub(findString, replacementString, 1) -- Replace the alias name in the frame with the expanded and filtered string&lt;br /&gt;
					shouldPin = true -- If we match with an expanded alias then we have to pin it&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- Save modified frame to proper location&lt;br /&gt;
			if isDesiredItem or shouldPin or (restrictToMatching and outputPinnedFrameCount[frameCount]) then&lt;br /&gt;
				table.insert(pinFrames, frameStr)&lt;br /&gt;
				pinnedFrameCount = pinnedFrameCount + frameCount&lt;br /&gt;
				-- Don&amp;#039;t pin an alias, unless its an exact match&lt;br /&gt;
				if not isOutput and (not isAlias and isDesiredItem) then&lt;br /&gt;
					pinnedFramesIndex[frameCount] = true -- When we find a good entry, store the number for use by Output&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(allFrames, frameStr)&lt;br /&gt;
			allFrameCount = allFrameCount + frameCount&lt;br /&gt;
		end&lt;br /&gt;
		if pinnedFrameCount &amp;gt; 0 then&lt;br /&gt;
			if pinnedFrameCount &amp;lt; allFrameCount then&lt;br /&gt;
				shouldPinOutput = true&lt;br /&gt;
			end&lt;br /&gt;
			for k,v in pairs(pinnedFramesIndex) do&lt;br /&gt;
				outputPinnedFrameCount[k] = v&lt;br /&gt;
			end&lt;br /&gt;
			return table.concat(pinFrames, &amp;#039;;&amp;#039;)&lt;br /&gt;
		else&lt;br /&gt;
			return table.concat(allFrames, &amp;#039;;&amp;#039;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- for A1, A2, A3, B1, B2, etc&lt;br /&gt;
	for _, arg in ipairs(crafting.cArgVals) do&lt;br /&gt;
		craftingArgs[arg] = pinFrames(craftingArgs[arg])&lt;br /&gt;
	end&lt;br /&gt;
	craftingArgs.Output = pinFrames(craftingArgs.Output, shouldPinOutput, true)&lt;br /&gt;
	&lt;br /&gt;
	return craftingArgs&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[The main body, which retrieves the data, and returns the relevant&lt;br /&gt;
	crafting templates, sorted alphabetically&lt;br /&gt;
--]]&lt;br /&gt;
function p.dpl(f)&lt;br /&gt;
	local args = f&lt;br /&gt;
	if f == mw.getCurrentFrame() then&lt;br /&gt;
		args = f:getParent().args&lt;br /&gt;
	else&lt;br /&gt;
		f = mw.getCurrentFrame()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local startingIngredients = args[1] and text.split(args[1], &amp;#039;%s*,%s*&amp;#039;) or {titleText}&lt;br /&gt;
	local seen = {}&lt;br /&gt;
	local ingredients = {}&lt;br /&gt;
	&lt;br /&gt;
	-- Loop through all defined ingredients, and expand any aliases.&lt;br /&gt;
	for _,entry in pairs(startingIngredients) do&lt;br /&gt;
		if not seen[entry] then&lt;br /&gt;
			table.insert(ingredients, entry)&lt;br /&gt;
			seen[entry] = true&lt;br /&gt;
			local expandedAlias = aliases[entry]&lt;br /&gt;
&lt;br /&gt;
			if expandedAlias then&lt;br /&gt;
				for _,a in pairs(expandedAlias) do&lt;br /&gt;
					if not seen[a] then&lt;br /&gt;
						table.insert(ingredients, (a.name or a))&lt;br /&gt;
						seen[a] = true	&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local showDescription&lt;br /&gt;
	local templates = {}&lt;br /&gt;
	&lt;br /&gt;
	local queryStrings = {}&lt;br /&gt;
	-- SMW can query up to 15 conditions at once, so group ingredients into 15&lt;br /&gt;
	local count = 1&lt;br /&gt;
	while count &amp;lt;= #ingredients do&lt;br /&gt;
		queryStrings[math.floor(count/15)+1] = table.concat(ingredients, &amp;#039;||&amp;#039;, count, math.min(#ingredients, count + 14))&lt;br /&gt;
		count = count + 15&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local seen = {}&lt;br /&gt;
	for _,str in ipairs(queryStrings) do&lt;br /&gt;
		local query = {&lt;br /&gt;
			&amp;#039;[[Crafting ingredient::&amp;#039;..str..&amp;#039;]]&amp;#039;,&lt;br /&gt;
			&amp;#039;?Crafting JSON&amp;#039;,&lt;br /&gt;
			&amp;#039;?-Has subobject#-=Source page&amp;#039;,&lt;br /&gt;
			limit = 500&lt;br /&gt;
		}&lt;br /&gt;
		local smwdata = mw.smw.ask(query)&lt;br /&gt;
		&lt;br /&gt;
		if smwdata then&lt;br /&gt;
			for _,v in ipairs(smwdata) do&lt;br /&gt;
				if v[&amp;#039;Source page&amp;#039;] ~= titleText then -- Do not display results that came from the same page we are operating on, as they will be outdated.&lt;br /&gt;
					if type(v[&amp;#039;Crafting JSON&amp;#039;]) ~= &amp;quot;table&amp;quot; then --If a subobject name is not unique enough it will return as a table.&lt;br /&gt;
						if seen[v[&amp;#039;Crafting JSON&amp;#039;]] == nil then&lt;br /&gt;
							seen[v[&amp;#039;Crafting JSON&amp;#039;]] = 1&lt;br /&gt;
							local tArgs = mw.text.jsonDecode(v[&amp;#039;Crafting JSON&amp;#039;])&lt;br /&gt;
							tArgs[&amp;#039;ignoreusage&amp;#039;] = &amp;#039;1&amp;#039; -- Always set ignore usage for crafting invocations that are usage.&lt;br /&gt;
							if tArgs.description and tArgs.description ~= &amp;#039;&amp;#039; then&lt;br /&gt;
								showDescription = &amp;#039;1&amp;#039;&lt;br /&gt;
							end&lt;br /&gt;
							local newArgs = filterFrames(tArgs, startingIngredients)&lt;br /&gt;
							table.insert(templates,{args = newArgs,	sortKey = newArgs.Output or newArgs.name})&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						mw.log(&amp;quot;ERROR: query returned table.&amp;quot;)&lt;br /&gt;
						mw.logObject(v[&amp;#039;Crafting JSON&amp;#039;])&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local templateCount = #templates&lt;br /&gt;
	if templateCount == 0 then&lt;br /&gt;
		if mw.title.getCurrentTitle().nsText == &amp;#039;&amp;#039; then&lt;br /&gt;
			return f:expandTemplate{title=&amp;#039;Translation category&amp;#039;, args={i18n.emptyCategory, project=&amp;#039;0&amp;#039;}}&lt;br /&gt;
		end&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	table.sort(templates, function(a, b)&lt;br /&gt;
		if not a then return b end&lt;br /&gt;
		if not b then return a end&lt;br /&gt;
		return a.sortKey &amp;lt; b.sortKey&lt;br /&gt;
	end)&lt;br /&gt;
	&lt;br /&gt;
	local initialArgs = templates[1].args&lt;br /&gt;
	initialArgs.head = &amp;#039;1&amp;#039;&lt;br /&gt;
	initialArgs.showname = &amp;#039;1&amp;#039;&lt;br /&gt;
	initialArgs.showdescription = showDescription&lt;br /&gt;
	if not args.continue then&lt;br /&gt;
		templates[templateCount].args.foot = &amp;#039;1&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local out = {}&lt;br /&gt;
	for i, template in ipairs(templates) do&lt;br /&gt;
		out[i] = crafting.table(template.args)&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(out, &amp;#039;\n&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>minecraft&gt;ThermoF</name></author>
	</entry>
</feed>