Module:Protocol version

From Minecraft Wiki
Jump to navigation Jump to search
local p = {}

local function getVersion( version, dataType, nocat )
	if not version or not dataType then
		return nil
	end
	dataType = dataType:lower()

	local typeDatas = {
		protocol = {
			template = 'Template:Protocol version#Unknown version',
			category = 'Category:Unknown protocol version'
		},
		data = {
			template = 'Template:Data version#Unknown version',
			category = 'Category:Unknown data version'
		},
		res = {
			template = 'Template:Resource pack version#Unknown version',
			category = 'Category:Unknown resource pack version'
		},
		dat = {
			template = 'Template:Data pack version#Unknown version',
			category = 'Category:Unknown data pack version'
		}
	}
	-- load the values from the submodule
	local dataSource = mw.loadData( 'Module:Protocol version/Versions' )
	local versionData = dataSource.versions[ version ]
	local definedTypes = dataSource.types
	if versionData then
		typeDatas.protocol.data = versionData.protocol
		typeDatas.data.data = versionData.data
		typeDatas.res.data = versionData.res
		typeDatas.dat.data = versionData.dat
	end

	local result = nil
	local linkText = nil
	if versionData then
		if typeDatas[ dataType ].data then
			if typeDatas[ dataType ].data == definedTypes.unknown then
				linkText = definedTypes.unknown
			else
				if type( typeDatas[ dataType ].data ) == 'number' and typeDatas[ dataType ].data >= 0x40000000 then
					result = string.format( '%#x', typeDatas[ dataType ].data )
				elseif ( dataType == 'res' or dataType == 'dat' ) and type( typeDatas[ dataType ].data ) == 'table' then
					result = string.format( '%s.%s', typeDatas[ dataType ].data.major or typeDatas[ dataType ].data[ 1 ] or '0', typeDatas[ dataType ].data.minor or typeDatas[ dataType ].data[ 2 ] or '0' )
				else
					result = typeDatas[ dataType ].data
				end
			end
		else
			result = definedTypes.none
		end
	else
		linkText = definedTypes.pending
	end
	if linkText and not result then
		result = string.format( '[[%s|%s]]', typeDatas[ dataType ].template, linkText )
		if not nocat and mw.title.getCurrentTitle().namespace == 0 and not mw.title.getCurrentTitle().isSubpage then
			result = result .. string.format( '[[%s]]', typeDatas[ dataType ].category )
		end
	end
	return result
end

-- {{Protocol version}}
function p.protocol( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	return getVersion( mw.text.trim( args[ 1 ] or '' ), 'protocol', args.nocat )
end

-- {{Data version}}
function p.data( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	return getVersion( mw.text.trim( args[ 1 ] or '' ), 'data', args.nocat )
end

-- {{Resource pack version}}
function p.resourcePack( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	return getVersion( mw.text.trim( args[ 1 ] or '' ), 'res', args.nocat )
end

-- {{Data pack version}}
function p.dataPack( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	return getVersion( mw.text.trim( args[ 1 ] or '' ), 'dat', args.nocat )
end

-- Version table ({{Protocol version/table}})
function p.table( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	
	local lastVers = {}
	for v in mw.text.gsplit( mw.text.trim( args.lastvers or '' ), ',', true ) do
		v = mw.text.trim( v )
		if v ~= '' then
			table.insert( lastVers, v )
		end
	end

	local result = {}
	local dataSource = mw.loadData( 'Module:Protocol version/Versions' )
	local definedTypes = dataSource.types
	for _, group in ipairs( dataSource.groups ) do
		local include = true
		if #args ~= 0 then
			include = false
			for _, name in ipairs( args ) do
				if name == group.name then
					include = true
					break
				end
			end
		end

		if include then
			local displayControl = {
				protocol = not args.hideprotocol,
				data = group.optional.data and not args.hidedata,
				resPack = group.optional.resPack and not args.hiderespack,
				datPack = group.optional.datPack and not args.hidedatpack,
			}
			if not displayControl.protocol and not displayControl.data and not displayControl.resPack and not displayControl.datPack then
				break
			end

			if not args.notitle then
				table.insert( result, string.format( '<h3>[[%s|%s]]</h3>', group.link, group.name ) )
			end
			if group.desc ~= nil then
				table.insert( result, group.desc )
			end
			local htmlTable = mw.html.create( 'table' ):addClass( 'wikitable sortable jquery-tablesorter' )
			local htmlTableHeader = mw.html.create( 'tr' )
			htmlTableHeader:tag( 'th' ):wikitext( 'Client version' ):done()
			if displayControl.protocol then
				htmlTableHeader:tag( 'th' ):wikitext( '[[Protocol version]]' ):done()
			end
			if displayControl.data then
				htmlTableHeader:tag( 'th' ):wikitext( '[[Data version]]' ):done()
			end
			if displayControl.resPack then
				htmlTableHeader:tag( 'th' ):wikitext( '[[Resource pack format]]' ):done()
			end
			if displayControl.datPack then
				htmlTableHeader:tag( 'th' ):wikitext( '[[Data pack format]]' ):done()
			end
			htmlTable:node( htmlTableHeader )

			local rows = {}
			local rowFirst = '<td style="text-align:center">%s</td>'
			local rowMerged = '<td style="text-align:center" rowspan="%s">%s</td>'
			local ctrl = {
				pv = { prev = -1 },
				dv = { prev = -1 },
				rp = { prev = -1 },
				dp = { prev = -1 },
			}
			local displayedProtocol = ''
			for _, version in ipairs( group.values ) do
				table.insert( rows, '<tr>' )
				table.insert( rows, string.format( '<td>[[%s]]</td>', version.name ) )
				displayedProtocol = version.protocol
				if type( displayedProtocol ) == 'number' and displayedProtocol >= 0x40000000 then
					displayedProtocol = '0x' .. string.format( '%X', displayedProtocol ) .. '<br>(' .. displayedProtocol .. ')'
				end
				if displayControl.protocol then
					if version.protocol ~= ctrl.pv.prev or version.forceSplitProtocol then
						ctrl.pv.prev = version.protocol
						ctrl.pv.rowspan = 1
						table.insert( rows, rowFirst:format( displayedProtocol ) )
						ctrl.pv.idx = #rows
					else
						ctrl.pv.rowspan = ctrl.pv.rowspan + 1
						rows[ ctrl.pv.idx ] = rowMerged:format( ctrl.pv.rowspan, displayedProtocol )
					end
				end
				if displayControl.data then
					if version.data then
						if version.data ~= ctrl.dv.prev then
							ctrl.dv.prev = version.data
							ctrl.dv.rowspan = 1
							table.insert( rows, rowFirst:format( version.data ) )
							ctrl.dv.idx = #rows
						else
							ctrl.dv.rowspan = ctrl.dv.rowspan + 1
							rows[ ctrl.dv.idx ] = rowMerged:format( ctrl.dv.rowspan, version.data )
						end
					else
						if ctrl.dv.prev ~= definedTypes.none then
							ctrl.dv.prev = definedTypes.none
							ctrl.dv.rowspan = 1
							table.insert( rows, rowFirst:format( definedTypes.none ) )
							ctrl.dv.idx = #rows
						else
							ctrl.dv.rowspan = ctrl.dv.rowspan + 1
							rows[ ctrl.dv.idx ] = rowMerged:format( ctrl.dv.rowspan, definedTypes.none )
						end
					end
				end
				if displayControl.resPack then
					if version.res then
						local versionRes = version.res
						if type( versionRes ) == 'table' then
							versionRes = string.format( '%s.%s', versionRes.major or versionRes[ 1 ] or '0', versionRes.minor or versionRes[ 2 ] or '0' )
						end
						if versionRes ~= ctrl.rp.prev then
							ctrl.rp.prev = versionRes
							ctrl.rp.rowspan = 1
							table.insert( rows, rowFirst:format( versionRes ) )
							ctrl.rp.idx = #rows
						else
							ctrl.rp.rowspan = ctrl.rp.rowspan + 1
							rows[ ctrl.rp.idx ] = rowMerged:format( ctrl.rp.rowspan, versionRes )
						end
					else
						if ctrl.rp.prev ~= definedTypes.none then
							ctrl.rp.prev = definedTypes.none
							ctrl.rp.rowspan = 1
							table.insert( rows, rowFirst:format( definedTypes.none ) )
							ctrl.rp.idx = #rows
						else
							ctrl.rp.rowspan = ctrl.rp.rowspan + 1
							rows[ ctrl.rp.idx ] = rowMerged:format( ctrl.rp.rowspan, definedTypes.none )
						end
					end
				end
				if displayControl.datPack then
					if version.dat then
						local versionDat = version.dat
						if type( versionDat ) == 'table' then
							versionDat = string.format( '%s.%s', versionDat.major or versionDat[ 1 ] or '0', versionDat.minor or versionDat[ 2 ] or '0' )
						end
						if versionDat ~= ctrl.dp.prev then
							ctrl.dp.prev = versionDat
							ctrl.dp.rowspan = 1
							table.insert( rows, rowFirst:format( versionDat ) )
							ctrl.dp.idx = #rows
						else
							ctrl.dp.rowspan = ctrl.dp.rowspan + 1
							rows[ ctrl.dp.idx ] = rowMerged:format( ctrl.dp.rowspan, versionDat )
						end
					else
						if ctrl.dp.prev ~= definedTypes.none then
							ctrl.dp.prev = definedTypes.none
							ctrl.dp.rowspan = 1
							table.insert( rows, rowFirst:format( definedTypes.none ) )
							ctrl.dp.idx = #rows
						else
							ctrl.dp.rowspan = ctrl.dp.rowspan + 1
							rows[ ctrl.dp.idx ] = rowMerged:format( ctrl.dp.rowspan, definedTypes.none )
						end
					end
				end
				table.insert( rows, '</tr>' )
				local isLast = false
				for _, v in pairs( lastVers ) do
					if version.name == v then
						isLast = true
						break
					end
				end
				if isLast == true then
					break
				end
			end
			htmlTable:wikitext( table.concat( rows ) )
			table.insert( result, tostring( htmlTable ) )
		end
	end
	return table.concat( result )
end

return p