Skip to content
Merged
Show file tree
Hide file tree
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
11 changes: 9 additions & 2 deletions rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ const appConfig = defineConfig({
// 50kb limit for data uri
dataUriLimit: SINGLE_FILE_BUILD ? 1 * 1024 * 1024 * 1024 : 50 * 1024
},
performance: {
// prefetch: {
// include(filename) {
// return filename.includes('mc-data') || filename.includes('mc-assets')
// },
// },
},
source: {
entry: {
index: './src/index.ts',
Expand All @@ -154,7 +161,7 @@ const appConfig = defineConfig({
'process.platform': '"browser"',
'process.env.GITHUB_URL':
JSON.stringify(`https://github.com/${process.env.GITHUB_REPOSITORY || `${process.env.VERCEL_GIT_REPO_OWNER}/${process.env.VERCEL_GIT_REPO_SLUG}` || githubRepositoryFallback}`),
'process.env.DEPS_VERSIONS': JSON.stringify({}),
'process.env.ALWAYS_MINIMAL_SERVER_UI': JSON.stringify(process.env.ALWAYS_MINIMAL_SERVER_UI),
'process.env.RELEASE_TAG': JSON.stringify(releaseTag),
'process.env.RELEASE_LINK': JSON.stringify(releaseLink),
'process.env.RELEASE_CHANGELOG': JSON.stringify(releaseChangelog),
Expand Down Expand Up @@ -190,7 +197,7 @@ const appConfig = defineConfig({
childProcess.execSync('tsx ./scripts/optimizeBlockCollisions.ts', { stdio: 'inherit' })
}
// childProcess.execSync(['tsx', './scripts/genLargeDataAliases.ts', ...(SINGLE_FILE_BUILD ? ['--compressed'] : [])].join(' '), { stdio: 'inherit' })
genLargeDataAliases(SINGLE_FILE_BUILD)
genLargeDataAliases(SINGLE_FILE_BUILD || process.env.ALWAYS_COMPRESS_LARGE_DATA === 'true')
fsExtra.copySync('./node_modules/mc-assets/dist/other-textures/latest/entity', './dist/textures/entity')
fsExtra.copySync('./assets/background', './dist/background')
fs.copyFileSync('./assets/favicon.png', './dist/favicon.png')
Expand Down
5 changes: 4 additions & 1 deletion scripts/genLargeDataAliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const genLargeDataAliases = async (isCompressed: boolean) => {

let str = `${decoderCode}\nexport const importLargeData = async (mod: ${Object.keys(modules).map(x => `'${x}'`).join(' | ')}) => {\n`
for (const [module, { compressed, raw }] of Object.entries(modules)) {
let importCode = `(await import('${isCompressed ? compressed : raw}')).default`;
const chunkName = module === 'mcData' ? 'mc-data' : 'mc-assets';
let importCode = `(await import(/* webpackChunkName: "${chunkName}" */ '${isCompressed ? compressed : raw}')).default`;
if (isCompressed) {
importCode = `JSON.parse(decompressFromBase64(${importCode}))`
}
Expand All @@ -30,6 +31,8 @@ export const genLargeDataAliases = async (isCompressed: boolean) => {
const decoderCode = /* ts */ `
import pako from 'pako';

globalThis.pako = { inflate: pako.inflate.bind(pako) }

function decompressFromBase64(input) {
console.time('decompressFromBase64')
// Decode the Base64 string
Expand Down
80 changes: 59 additions & 21 deletions scripts/makeOptimizedMcData.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { dirname } from 'node:path'
import supportedVersions from '../src/supportedVersions.mjs'
import { gzipSizeFromFileSync } from 'gzip-size'
import fs from 'fs'
import {default as _JsonOptimizer} from '../src/optimizeJson'
import { gzipSync } from 'zlib';
import { default as _JsonOptimizer } from '../src/optimizeJson'
import { gzipSync } from 'zlib'
import MinecraftData from 'minecraft-data'
import MCProtocol from 'minecraft-protocol'

Expand All @@ -21,12 +21,12 @@ const require = Module.createRequire(import.meta.url)

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

function toMajor (version) {
function toMajor(version) {
const [a, b] = (version + '').split('.')
return `${a}.${b}`
}

const versions = {}
let versions = {}
const dataTypes = new Set()

for (const [version, dataSet] of Object.entries(dataPaths.pc)) {
Expand All @@ -42,6 +42,31 @@ const versionToNumber = (ver) => {
return +`${x.padStart(2, '0')}${y.padStart(2, '0')}${z.padStart(2, '0')}`
}

// Version clipping support
const minVersion = process.env.MIN_MC_VERSION
const maxVersion = process.env.MAX_MC_VERSION

// Filter versions based on MIN_VERSION and MAX_VERSION if provided
if (minVersion || maxVersion) {
const filteredVersions = {}
const minVersionNum = minVersion ? versionToNumber(minVersion) : 0
const maxVersionNum = maxVersion ? versionToNumber(maxVersion) : Infinity

for (const [version, dataSet] of Object.entries(versions)) {
const versionNum = versionToNumber(version)
if (versionNum >= minVersionNum && versionNum <= maxVersionNum) {
filteredVersions[version] = dataSet
}
}

versions = filteredVersions

console.log(`Version clipping applied: ${minVersion || 'none'} to ${maxVersion || 'none'}`)
console.log(`Processing ${Object.keys(versions).length} versions:`, Object.keys(versions).sort((a, b) => versionToNumber(a) - versionToNumber(b)))
}

console.log('Bundling version range:', Object.keys(versions)[0], 'to', Object.keys(versions).at(-1))

// if not included here (even as {}) will not be bundled & accessible!
// const compressedOutput = !!process.env.SINGLE_FILE_BUILD
const compressedOutput = true
Expand All @@ -57,18 +82,20 @@ const dataTypeBundling2 = {
}
}
const dataTypeBundling = {
language: {
language: process.env.SKIP_MC_DATA_LANGUAGE === 'true' ? {
raw: {}
} : {
ignoreRemoved: true,
ignoreChanges: true
},
blocks: {
arrKey: 'name',
processData (current, prev) {
processData(current, prev) {
for (const block of current) {
if (block.transparent) {
const forceOpaque = block.name.includes('shulker_box') || block.name.match(/^double_.+_slab\d?$/) || ['melon_block', 'lit_pumpkin', 'lit_redstone_ore', 'lit_furnace'].includes(block.name)

const prevBlock = prev?.find(x => x.name === block.name);
const prevBlock = prev?.find(x => x.name === block.name)
if (forceOpaque || (prevBlock && !prevBlock.transparent)) {
block.transparent = false
}
Expand Down Expand Up @@ -136,7 +163,9 @@ const dataTypeBundling = {
blockLoot: {
arrKey: 'block'
},
recipes: {
recipes: process.env.SKIP_MC_DATA_RECIPES === 'true' ? {
raw: {}
} : {
raw: true
// processData: processRecipes
},
Expand All @@ -150,7 +179,7 @@ const dataTypeBundling = {
// }
}

function processRecipes (current, prev, getData, version) {
function processRecipes(current, prev, getData, version) {
// can require the same multiple times per different versions
if (current._proccessed) return
const items = getData('items')
Expand Down Expand Up @@ -242,30 +271,39 @@ for (const [i, [version, dataSet]] of versionsArr.reverse().entries()) {
for (const [dataType, dataPath] of Object.entries(dataSet)) {
const config = dataTypeBundling[dataType]
if (!config) continue
if (dataType === 'blockCollisionShapes' && versionToNumber(version) >= versionToNumber('1.13')) {
// contents += ` get ${dataType} () { return window.globalGetCollisionShapes?.("${version}") },\n`
continue
}
const ignoreCollisionShapes = dataType === 'blockCollisionShapes' && versionToNumber(version) >= versionToNumber('1.13')

let injectCode = ''
const getData = (type) => {
const getRealData = (type) => {
const loc = `minecraft-data/data/${dataSet[type]}/`
const dataPathAbsolute = require.resolve(`minecraft-data/${loc}${type}`)
// const data = fs.readFileSync(dataPathAbsolute, 'utf8')
const dataRaw = require(dataPathAbsolute)
return dataRaw
}
const dataRaw = getData(dataType)
const dataRaw = getRealData(dataType)
let rawData = dataRaw
if (config.raw) {
rawDataVersions[dataType] ??= {}
rawDataVersions[dataType][version] = rawData
rawData = dataRaw
if (config.raw === true) {
rawData = dataRaw
} else {
rawData = config.raw
}

if (ignoreCollisionShapes && dataType === 'blockCollisionShapes') {
rawData = {
blocks: {},
shapes: {}
}
}
} else {
if (!diffSources[dataType]) {
diffSources[dataType] = new JsonOptimizer(config.arrKey, config.ignoreChanges, config.ignoreRemoved)
}
try {
config.processData?.(dataRaw, previousData[dataType], getData, version)
config.processData?.(dataRaw, previousData[dataType], getRealData, version)
diffSources[dataType].recordDiff(version, dataRaw)
injectCode = `restoreDiff(sources, ${JSON.stringify(dataType)}, ${JSON.stringify(version)})`
} catch (err) {
Expand Down Expand Up @@ -297,16 +335,16 @@ console.log('total size (mb)', totalSize / 1024 / 1024)
console.log(
'size per data type (mb, %)',
Object.fromEntries(Object.entries(sizePerDataType).map(([dataType, size]) => {
return [dataType, [size / 1024 / 1024, Math.round(size / totalSize * 100)]];
return [dataType, [size / 1024 / 1024, Math.round(size / totalSize * 100)]]
}).sort((a, b) => {
//@ts-ignore
return b[1][1] - a[1][1];
return b[1][1] - a[1][1]
}))
)

function compressToBase64(input) {
const buffer = gzipSync(input);
return buffer.toString('base64');
const buffer = gzipSync(input)
return buffer.toString('base64')
}

const filePath = './generated/minecraft-data-optimized.json'
Expand Down
6 changes: 6 additions & 0 deletions src/downloadAndOpenFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export const getFixedFilesize = (bytes: number) => {
return prettyBytes(bytes, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}

export const isInterestedInDownload = () => {
const { map, texturepack, replayFileUrl } = appQueryParams
const { mapDir } = appQueryParamsArray
return !!map || !!texturepack || !!replayFileUrl || !!mapDir
}

const inner = async () => {
const { map, texturepack, replayFileUrl } = appQueryParams
const { mapDir } = appQueryParamsArray
Expand Down
20 changes: 13 additions & 7 deletions src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,36 @@ declare namespace NodeJS {
interface ProcessEnv {
// Build configuration
NODE_ENV: 'development' | 'production'
SINGLE_FILE_BUILD?: string
MIN_MC_VERSION?: string
MAX_MC_VERSION?: string
ALWAYS_COMPRESS_LARGE_DATA?: 'true' | 'false'
SINGLE_FILE_BUILD?: 'true' | 'false'
WS_PORT?: string
DISABLE_SERVICE_WORKER?: string
DISABLE_SERVICE_WORKER?: 'true' | 'false'
CONFIG_JSON_SOURCE?: 'BUNDLED' | 'REMOTE'
LOCAL_CONFIG_FILE?: string
BUILD_VERSION?: string

// GitHub and Vercel related
// Build internals
GITHUB_REPOSITORY?: string
VERCEL_GIT_REPO_OWNER?: string
VERCEL_GIT_REPO_SLUG?: string

// UI and Features
// UI
MAIN_MENU_LINKS?: string
ALWAYS_MINIMAL_SERVER_UI?: 'true' | 'false'

// App features
ENABLE_COOKIE_STORAGE?: string
COOKIE_STORAGE_PREFIX?: string

// Release information
// Build info. Release information
RELEASE_TAG?: string
RELEASE_LINK?: string
RELEASE_CHANGELOG?: string

// Other configurations
DEPS_VERSIONS?: string
// Build info
INLINED_APP_CONFIG?: string
GITHUB_URL?: string
}
}
Loading
Loading