diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e17eb17..8a2d2190 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,10 @@ "source.fixAll.eslint": true } }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2 + }, "typescript.format.semicolons": "remove", "editor.insertSpaces": false, "files.insertFinalNewline": true, diff --git a/src/app/hooks/useAsync.ts b/src/app/hooks/useAsync.ts index 5cce9276..faf34c49 100644 --- a/src/app/hooks/useAsync.ts +++ b/src/app/hooks/useAsync.ts @@ -7,12 +7,15 @@ export function useAsync( fn: () => Promise, inputs: Inputs = [], initialState: AsyncState = { loading: true }, -): AsyncState { +): AsyncState & { refresh: () => Promise } { const [state, callback] = useAsyncFn Promise>(fn, inputs, initialState) useEffect(() => { callback() }, [callback]) - return state + return { + ...state, + refresh: callback, + } } diff --git a/src/app/pages/Guide.tsx b/src/app/pages/Guide.tsx index b382d14e..46715848 100644 --- a/src/app/pages/Guide.tsx +++ b/src/app/pages/Guide.tsx @@ -30,11 +30,17 @@ export function Guide({ id }: Props) { const { version, changeVersion } = useVersion() const { changeTitle } = useTitle() - const { value: content } = useAsync(async () => { + const { value: content, refresh } = useAsync(async () => { const res = await fetch(`../../guides/${id}.md`) return await res.text() }, [id]) + if ((import.meta as any).hot) { + (import.meta as any).hot.on('guide-update', (updateId: string) => { + if (id === updateId) refresh() + }) + } + const frontMatter = useMemo(() => { if (!content) return undefined const data = parseFrontMatter(content) diff --git a/src/guides/feature-order-cycle.md b/src/guides/feature-order-cycle.md new file mode 100644 index 00000000..b8c83eb0 --- /dev/null +++ b/src/guides/feature-order-cycle.md @@ -0,0 +1,76 @@ +--- +title: How to fix feature order cycles +versions: + - '1.18' + - '1.18.2' + - '1.19' +tags: + - worldgen + - biomes + - features +--- + +> java.lang.IllegalStateException: Feature order cycle found, involved biomes + +Are you getting this frustrating error? Let's look at why it happens and how to prevent it. + +## Why does it happen? +Feature order cycles happen when two biomes reference the same placed feature in the same step, but in a different order. + +Let's try with an example. We have two biomes here: +**`data/example/worldgen/biome/forest.json`** +```json +{ + ... + "features": [ + [], + [ + "example:blue_tree", + "example:red_tree", + "example:rocks", + ] + ] +} +``` + +**`data/example/worldgen/biome/plains.json`** +```json +{ + ... + "features": [ + [ + "example:blue_tree" + ], + [ + "example:rocks", + "example:blue_tree" + ] + ] +} +``` + +When we try to load these biomes, data pack validation will fail because in the `example:forest` biome in step 2, `blue_tree` is before `rocks`; while in the `example:plains` biome, `rocks` is before `blue_tree`. + +## How to fix it +The rule is that for each step in `"features"`, all features need to be ordered consistently across biomes. + +The above example can be fixed by swapping the features in step 2 of the `plains` biome: +**`data/example/worldgen/biome/plains.json`** +```json +{ + ... + "features": [ + [ + "example:blue_tree" + ], + [ + "example:blue_tree", + "example:rocks" + ] + ] +} +``` + +If your data pack is more complicated, with multiple biomes and lots of features, this will be a harder process. Since 1.18.2, the error will include the conflicting biome IDs. + +If you want more detailed errors, a useful mod is [Cyanide](https://www.curseforge.com/minecraft/mc-mods/cyanide-fabric). This will show the exact feature cycle that's causing problems, as well as other worldgen related errors. diff --git a/src/styles/global.css b/src/styles/global.css index f6fc1b10..b8293fa6 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1509,6 +1509,10 @@ hr { border-radius: 6px; } +.guide-card:not(:last-child) { + margin-bottom: 8px; +} + .guide-versions { color: var(--text-3); float: right; diff --git a/vite.config.js b/vite.config.js index 1e93f0aa..8c2a3705 100644 --- a/vite.config.js +++ b/vite.config.js @@ -22,6 +22,7 @@ const guides = glob.sync('src/guides/**/*.md').flatMap(g => { ...frontMatter, }] } catch (e) { + console.warn('Failed loading guide', g, e.message) return [] } }) @@ -88,6 +89,20 @@ export default defineConfig({ ], }), visualizer({ open: true }), + { + name: 'watch-guides', + enforce: 'post', + handleHotUpdate({ file, server }) { + const match = file.match(/src\/guides\/([a-z0-9-]+)\.md/) + if (match && match[1]) { + server.ws.send({ + type: 'custom', + event: 'guide-update', + data: match[1], + }) + } + }, + }, ], })