Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions src/transforms/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ const merge = require('lodash.merge')
const minecraftData = require('minecraft-data')
const protocols = {}

// The generated code is fully determined by these versions plus the protocol
// key and customPackets, so together they make a stale cache file unreachable.
function protocolCacheFile (state, direction, version, customPackets) {
const cacheDir = process.env.NMP_PROTOCOL_CACHE_DIR ??
require('path').join(require('os').tmpdir(), 'node-minecraft-protocol-cache')
if (cacheDir === '0') return null
const inputs = [
require('../../package.json').version,
require('protodef/package.json').version,
require('minecraft-data/package.json').version,
JSON.stringify(customPackets ?? {})
].join(';')
const hash = require('crypto').createHash('sha1').update(inputs).digest('hex').slice(0, 12)
const name = `${version}-${state}-${direction}-${hash}.js`.replace(/[^a-zA-Z0-9.-]/g, '_')
return require('path').join(cacheDir, name)
}

function createProtocol (state, direction, version, customPackets, compiled = true) {
const key = `${state};${direction};${version}${compiled ? ';c' : ''}`
if (protocols[key]) { return protocols[key] }
Expand All @@ -24,18 +41,31 @@ function createProtocol (state, direction, version, customPackets, compiled = tr
throw new Error(`Unsupported protocol version '${versionInfo.version}' (attempted to use '${mcData.version.version}' data); try updating your packages with 'npm update'`)
}

const mergedProtocol = merge(mcData.protocol, customPackets?.[mcData.version.majorVersion] ?? {})

if (compiled) {
const compiler = new ProtoDefCompiler()
compiler.addTypes(require('../datatypes/compiler-minecraft'))
compiler.addProtocol(mergedProtocol, [state, direction])
nbt.addTypesToCompiler('big', compiler)
const proto = compiler.compileProtoDefSync()
const cacheFile = protocolCacheFile(state, direction, version, customPackets)
let proto
if (cacheFile) {
// A hit also skips loading mcData.protocol and walking it in
// addProtocol, which cost as much as the compile itself.
try { proto = compiler.loadCompiledProtoDefSync(cacheFile) } catch {}
}
if (!proto) {
const mergedProtocol = merge(mcData.protocol, customPackets?.[mcData.version.majorVersion] ?? {})
compiler.addProtocol(mergedProtocol, [state, direction])
// Registered a second time: the nbt schemas must override the types the
// protocol declares as native (the pre-cache call above only provides
// the natives needed to load a cached protocol).
nbt.addTypesToCompiler('big', compiler)
proto = compiler.compileProtoDefSync(cacheFile ? { cacheFile } : {})
}
protocols[key] = proto
return proto
}

const mergedProtocol = merge(mcData.protocol, customPackets?.[mcData.version.majorVersion] ?? {})
const proto = new ProtoDef(false)
proto.addTypes(minecraft)
proto.addProtocol(mergedProtocol, [state, direction])
Expand Down
Loading