import { useCallback, useMemo, useRef, useState } from 'preact/hooks' import config from '../../Config.js' import { useVersion } from '../../contexts/Version.jsx' import { stringifySource } from '../../services/Source.js' import { deepClone, deepEqual, writeZip } from '../../Utils.js' import { Btn } from '../Btn.jsx' import { ErrorPanel } from '../ErrorPanel.jsx' import { Octicon } from '../Octicon.jsx' import { BasicSettings } from './BasicSettings.jsx' import { BiomesSettings } from './BiomesSettings.jsx' import { generateCustomized } from './CustomizedGenerator.js' import { CustomizedModel } from './CustomizedModel.js' import { OresSettings } from './OresSettings.jsx' import { StructuresSettings } from './StructuresSettings.jsx' interface Props { tab: string | undefined } export function CustomizedPanel({ tab }: Props) { const { version } = useVersion() const [model, setModel] = useState(CustomizedModel.getDefault(version)) const changeModel = useCallback((change: Partial) => { setModel(m => ({ ...m, ...change })) }, []) const initialModel = useMemo(() => { return CustomizedModel.getDefault(version) }, [version]) const isModified = useMemo(() => { return !deepEqual(model, initialModel) }, [model, initialModel]) const reset = useCallback(() => { setModel(deepClone(initialModel)) }, [initialModel]) const download = useRef(null) const [error, setError] = useState(null) const [hasDownloaded, setHasDownloaded] = useState(false) const generate = useCallback(async () => { if (!download.current) return try { const pack = await generateCustomized(model, version) const entries = Object.entries(pack).flatMap(([type, files]) => { const prefix = `data/minecraft/${type}/` return [...files.entries()].map(([name, data]) => { const text = stringifySource(JSON.stringify(data, null, 2), 'json') return [prefix + name + '.json', new TextEncoder().encode(text)] as [string, Uint8Array] }) }) const pack_format = config.versions.find(v => v.id === version)!.pack_format const packMcmetaText = stringifySource(JSON.stringify({ pack: { pack_format, description: 'Customized world from misode.github.io' } }, null, 2), 'json') entries.push(['pack.mcmeta', new TextEncoder().encode(packMcmetaText)]) const url = await writeZip(entries) download.current.setAttribute('href', url) download.current.setAttribute('download', 'customized.zip') download.current.click() setHasDownloaded(true) setError(null) } catch (e) { if (e instanceof Error) { e.message = `Something went wrong creating the customized pack: ${e.message}` setError(e) } } }, [model, version]) return <>
{tab === 'basic' && } {tab === 'biomes' && } {tab === 'structures' && } {tab === 'ores' && }
{isModified && }
{error && setError(null)} body={`\n### Customized settings\n
\n
\n${JSON.stringify(getDiffModel(model, initialModel), null, 2)}\n
\n
\n`} />} {hasDownloaded &&

{Octicon.mortar_board} What now?

  1. After launching Minecraft, create a new singleplayer world.
  2. Select the "More" tab at the top.
  3. Click on "Data Packs" and drag the downloaded zip file onto the game window.
  4. Move the imported data pack to the right panel and click on "Done".
  5. A message will warn about the use of experimental world settings. Click on "Proceed".
} } function getDiffModel(model: any, initial: any) { const result = deepClone(model) if (typeof result !== 'object' || result === null) return Object.keys(result).forEach(key => { if (deepEqual(result[key], initial[key])) { delete result[key] } else if (typeof result[key] === 'object' && result[key] !== null) { result[key] = getDiffModel(result[key], initial[key]) } }) return result }