Skip to content

Commit

Permalink
use protodef-yaml to generate pc docs (#953)
Browse files Browse the repository at this point in the history
  • Loading branch information
extremeheat authored Jan 8, 2025
1 parent 76b0be5 commit 338742d
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 95 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
bundle.js
bundle.*
protocol
node_modules/
package-lock.json
144 changes: 106 additions & 38 deletions compileProtocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,122 @@ const { parse, genHTML } = require('protodef-yaml')
const mcData = require('minecraft-data')
const dataPath = join(dirname(require.resolve('minecraft-data')), 'minecraft-data/data/')

function createDocs () {
fs.writeFileSync('packet_map.yml', '!import: types.yml')
const inter = parse('proto.yml', true, true)
const version = inter['!version']
const html = genHTML(inter, { includeHeader: true })
const out = `${__dirname}/protocol/bedrock/${version}`
fs.mkdirSync(out, { recursive: true })
fs.writeFileSync(`${out}/index.html`, html)
fs.unlinkSync('packet_map.yml')
return `bedrock/${version}`
}

function main (dir, ver = 'latest') {
process.chdir(join(dir, ver))
if (!fs.existsSync('./proto.yml')) return
return createDocs(ver)
}

const makeHp = list => `
const makeHp = (pcList, bedrockList) => `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Protocol Versions</title>
<style>
html, body { width: 100%; height: 100%; font-family: sans-serif; padding: 0; margin: 0; }
.container { display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; min-height: 100vh; }
.version { padding: 10px; margin: 10px; font-size: 18px; height: 5%; border: 2px solid paleturquoise; font-weight: bold; text-align: center; }
.version:hover { background-color: paleturquoise; }
a { text-decoration: none; }
</style>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Protocol Versions</title>
<style>
html, body { width: 100%; height: 100%; font-family: sans-serif; padding: 0; margin: 0; }
.container { text-align: center; }
.versions { display: ruby; }
.version { padding: 10px; margin: 10px; font-size: 18px; height: 5%; border: 2px solid paleturquoise; font-weight: bold; text-align: center; }
.version:hover { background-color: paleturquoise; }
a { text-decoration: none; }
</style>
</head>
<body>
<div class='container'>
<h3>Minecraft Bedrock Protocol Docs</h3>
${list}
<h2>Protocol docs</h2>
<h3>Minecraft Java Edition</h3>
<div class="versions">${pcList}</div>
<h3>Minecraft Bedrock Edition protocol docs</h3>
<div class="versions">${bedrockList}</div>
</div>
</body>
</html>
`
let out = []
for (const version of [...mcData.supportedVersions.bedrock, 'latest']) {
console.log(version)
let ret = main(dataPath + 'bedrock/', version)

if (ret) out.push(`<div class="version"><a href="${ret}">${version}</a></div>`)
const createDocs = {
bedrock () {
fs.writeFileSync('packet_map.yml', '!import: types.yml')
const inter = parse('proto.yml', true, true)
const version = inter['!version']
const html = genHTML(inter, { includeHeader: true })
const out = join(__dirname, 'protocol/bedrock/', version.toString())
fs.mkdirSync(out, { recursive: true })
fs.writeFileSync(`${out}/index.html`, html)
fs.unlinkSync('packet_map.yml')
return `bedrock/${version}`
},
pc () {
let inter = parse('proto.yml', true, true)
const version = inter['!version']
try {
inter = prepareMcpc(inter)
} catch (e) {
console.log(e)
}
const html = genHTML(inter, { includeHeader: true, schemaSegmented: true })
const out = join(__dirname, 'protocol/pc/', version.toString())
fs.mkdirSync(out, { recursive: true })
fs.writeFileSync(`${out}/index.html`, html)
return `pc/${version}`
}
}

function main (edition, dir, ver = 'latest') {
process.chdir(join(dir, ver))
if (!fs.existsSync('./proto.yml')) return
return createDocs[edition](ver)
}

fs.writeFileSync(join(__dirname, '/protocol/index.html'), makeHp(out.reverse().join('\n')))
const out = { pc: [], bedrock: [] }
for (const edition of ['pc', 'bedrock']) {
for (const version of [...mcData.supportedVersions[edition], 'latest']) {
console.log(edition, version)
const ret = main(edition, dataPath + edition + '/', version)
if (ret) out[edition].push(`<div class="version"><a href="${ret}">${version}</a></div>`)
}
}

fs.writeFileSync(join(__dirname, '/protocol/index.html'), makeHp(
out.pc.reverse().join('\n'),
out.bedrock.reverse().join('\n')
))

// Add additional information to the schema before passing to HTML gen
function prepareMcpc (intermediary) {
const updated = structuredClone(intermediary)
function get (x, y) {
if (!x) return
for (const k in x) {
const [, n] = k.split(',')
if (n === y) return x[k]
}
}
for (const key in updated) {
if (key.startsWith('%container,^')) {
const region = key.split(',')[1].replace('^', '')
const [status, direction] = region.split('.')
const entries = updated[key]
const packetMapper = entries['%container,packet,']
const packetMapperName = get(packetMapper, 'name')
if (packetMapper && packetMapperName) {
const n = Object.entries(packetMapperName)
const p = Object.fromEntries(Object.entries(packetMapper['%switch,params,name'] ?? {}).map(([k, v]) => [k.replace('if ', ''), v]))
const packetMap = Object.fromEntries(n.map(([k, v]) => [p[v], k.split(',')[1]]))
for (const k in entries) {
if (!entries[k]) continue
if (k.startsWith('%container,')) {
const [, name] = k.split(',')
const id = parseInt(packetMap[name])
entries[k]['!typedoc'] = `${status} / ${direction} / ${name}`
if (isNaN(id)) {
entries[k]['!id'] = packetMap[name]
} else {
const hex = '0x' + id.toString(16).padStart(2, '0')
entries[k]['!id'] = id
entries[k]['!typedoc'] += ` (${hex})`
}
entries[k]['!bound'] = direction === 'toServer' ? 'server' : 'client'
}
}
}
}
}
return updated
}
12 changes: 6 additions & 6 deletions data.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
module.exports = () => {
const parameters = Object.fromEntries(new URLSearchParams(window.location.search))

const rawVersion = parameters['v']
const rawVersion = parameters.v
const version = rawVersion || '1.16.1'
const rawActive = parameters['d']
const rawActive = parameters.d
const active = rawActive || 'items'

const enums = ['biomes', 'instruments', 'items', 'materials', 'blocks', 'recipes', 'entities', 'protocol', 'windows', 'effects']

const enumsValues = ['biomes', 'instruments', 'items', 'blocks', 'entities', 'protocol', 'windows', 'effects']

return {
version: version,
active: active,
enums: enums,
enumsValues: enumsValues
version,
active,
enums,
enumsValues
}
}
2 changes: 1 addition & 1 deletion display_schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const docson = require('docson')

function displaySchema (enums) {
return Promise.all(enums.map(function (json) {
if (json === 'protocol') return
if (json === 'protocol') return null
return docson.doc(json, require('minecraft-data').schemas[json])
}))
}
Expand Down
10 changes: 5 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@
<h1>Please wait...</h1>
</div>
</div>
<script src="https://cdn.rawgit.com/skyzyx/dombuilder/1.3/dombuilder.min.js"></script>
<script async src="https://cdn.rawgit.com/skyzyx/dombuilder/1.3/dombuilder.min.js"></script>
<script>
class WebView extends HTMLElement {
scrollCallback = () => {
if (!document.getElementById(location.hash) && location.hash) {
this.shadowRoot.querySelector(location.hash)?.scrollIntoView({ behavior: 'smooth' })
if (!document.getElementById(location.hash.slice(1)) && location.hash) {
this.shadowRoot.getElementById(location.hash.slice(1))?.scrollIntoView({ behavior: 'smooth' })
}
}
connectedCallback() {
Expand All @@ -79,6 +79,6 @@ <h1>Please wait...</h1>

window.customElements.define('html-view', WebView)
</script>
<script src="./bundle.js"></script>
<script async src="./bundle.js"></script>
</body>
</html>
</html>
44 changes: 22 additions & 22 deletions loadProtocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ renderer.table = function (header, body) {
marked.setOptions({
gfm: true,
tables: true,
renderer: renderer
renderer
})

const _ = DOMBuilder
Expand All @@ -34,25 +34,27 @@ function flatten (array, mutable) {

function protocolToString (protocol, comments) {
return _('div#protocolActualTable')._(
flatten(protocol['toClient'] ? directionsToLines('', protocol, comments) : Object.keys(protocol).filter(function (state) { return state !== 'types' }).map(function (state) {
return [_('h1').text(state),
directionsToLines(state, protocol[state], comments && comments[state])]
}))
flatten(protocol.toClient
? directionsToLines('', protocol, comments)
: Object.keys(protocol).filter(function (state) { return state !== 'types' }).map(function (state) {
return [_('h1').text(state),
directionsToLines(state, protocol[state], comments && comments[state])]
}))
).H()
}

function directionsToLines (state, directions, comments) {
return [_('h2').text('toClient'), directionToLines(state, 'toClient', directions['toClient'].types, comments && comments['toClient']),
_('h2').text('toServer'), directionToLines(state, 'toServer', directions['toServer'].types, comments && comments['toServer'])]
return [_('h2').text('toClient'), directionToLines(state, 'toClient', directions.toClient.types, comments && comments.toClient),
_('h2').text('toServer'), directionToLines(state, 'toServer', directions.toServer.types, comments && comments.toServer)]
}

function reverseObject (o) {
return Object.keys(o).reduce(function (acc, k) { acc[o[k]] = k; return acc }, {})
}

function directionToLines (state, direction, packets, comments) {
const typesToNames = reverseObject(packets['packet'][1][1]['type'][1]['fields'])
const namesToIds = reverseObject(packets['packet'][1][0]['type'][1]['mappings'])
const typesToNames = reverseObject(packets.packet[1][1].type[1].fields)
const namesToIds = reverseObject(packets.packet[1][0].type[1].mappings)
return Object.keys(packets).filter(function (packetName) { return packetName !== 'packet' }).map(function (packetType) {
const packetName = typesToNames[packetType]
const packetId = namesToIds[packetName]
Expand Down Expand Up @@ -155,13 +157,15 @@ function switchToLines (totalCols, field, fieldType, depth, getVal) {
// First, group together lines
const elems = Object.keys(fieldType.typeArgs.fields).reduce(function (acc, key) {
const k = JSON.stringify(fieldType.typeArgs.fields[key])
if (acc.hasOwnProperty(k)) { acc[k].push(key) } else { acc[k] = [key] }
if (Object.hasOwn(acc, k)) { acc[k].push(key) } else { acc[k] = [key] }
return acc
}, {})
let lines = Object.keys(elems).reduce(function (acc, key) {
acc = acc.concat(fieldToLines(totalCols, { 'name': (firstLine ? '' : 'else ') +
acc = acc.concat(fieldToLines(totalCols, {
name: (firstLine ? '' : 'else ') +
'if (' + eqs(fieldType.typeArgs.compareTo, elems[key]) + ')',
'type': JSON.parse(key) }, depth + 1, getVal))
type: JSON.parse(key)
}, depth + 1, getVal))
firstLine = false
return acc
}, [])
Expand All @@ -170,7 +174,7 @@ function switchToLines (totalCols, field, fieldType, depth, getVal) {
.map(JSON.parse.bind(JSON))
.map(function (item) { return { type: item } })
if (fieldType.typeArgs.default && fieldType.typeArgs.default !== 'void') {
lines = lines.concat(fieldToLines(totalCols, { 'name': 'else', 'type': fieldType.typeArgs.default }, depth + 1, getVal))
lines = lines.concat(fieldToLines(totalCols, { name: 'else', type: fieldType.typeArgs.default }, depth + 1, getVal))
x.push({ type: fieldType.typeArgs.default })
}
if (lines.length > 0) {
Expand Down Expand Up @@ -232,7 +236,7 @@ function containerToLines (totalCols, field, fieldType, depth, getVal) {
function uniq (a) {
const seen = {}
return a.filter(function (item) {
return seen.hasOwnProperty(item) ? false : (seen[item] = true)
return Object.hasOwn(seen, item) ? false : (seen[item] = true)
})
}

Expand Down Expand Up @@ -275,7 +279,7 @@ function countCols (fields) {
}

function getFieldInfo (type) {
if (typeof type === 'string') { return { 'type': type } } else if (Array.isArray(type)) { return { 'type': type[0], 'typeArgs': type[1] } } else { return type }
if (typeof type === 'string') { return { type } } else if (Array.isArray(type)) { return { type: type[0], typeArgs: type[1] } } else { return type }
}

function objValues (obj) {
Expand All @@ -291,15 +295,11 @@ function eqs (compareTo, k) {
}, compareTo + ' == ' + k[0])
}

const dataPaths = require('minecraft-data/minecraft-data/data/dataPaths.json')

function loadProtocol (version) {
if (version.startsWith('bedrock')) {
const [, v] = version.split('_')
const path = dataPaths.bedrock[v].protocol
$j('#protocolTable').html(`<html-view src="protocol/${path}"><a href="protocol/${path}">Click here</a></html-view>`)
const data = require('minecraft-data')(version)
if (data.proto) {
$j('#protocolTable').html(`<html-view src="protocol/${data.proto}"><a href="protocol/${data.proto}">Click here</a></html-view>`)
} else {
const data = require('minecraft-data')(version).protocol
const comments = require('minecraft-data')(version).protocolComments
$j('#protocolTable').html(protocolToString(data, comments))
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"browserify": "^17.0.0",
"http-server": "^0.12.3",
"protodef-yaml": "^1.2.2",
"standard": "^12.0.1",
"standard": "^17.1.2",
"uglify-js": "^3.17.0"
}
}
Loading

0 comments on commit 338742d

Please sign in to comment.