diff --git a/README.md b/README.md index 204a73e0..a8928166 100644 --- a/README.md +++ b/README.md @@ -13,18 +13,6 @@ npm run dev ``` 4. Open the browser in `localhost:3000`. -## Guides -Do you want to contribute a [guide](https://misode.github.io/guides/)? -1. Add a markdown file in `src/guides/`. It's name will be used in the url. -2. The beginning of the file contains the metadata of the guide, check the other guides for the format. -3. Start the dev server with `npm run dev`. -4. If everything is setup, saving the markdown file will update the guide in the browser. -5. To support multiple versions, wrap parts of the guide like this: -``` -{#[1.18] this text will only show when 1.18 is selected #} -The selected version is {#version#}, and the pack format is {#pack_format#} -``` - ## Translating misode.github.io supports multiple languages. If you'd like to help us translate this project to your language, it would be really appreciated! If your language is not on this list, please create an issue for it. diff --git a/package-lock.json b/package-lock.json index e5c2c053..28a9e7af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,6 @@ "@typescript-eslint/parser": "^5.28.0", "autoprefixer": "^10.4.16", "eslint": "^8.17.0", - "fast-glob": "^3.2.11", "postcss": "^8.4.31", "preact": "^10.8.0", "preact-router": "^3.2.1", diff --git a/package.json b/package.json index 04a214ad..35d4d33f 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,6 @@ "@typescript-eslint/parser": "^5.28.0", "autoprefixer": "^10.4.16", "eslint": "^8.17.0", - "fast-glob": "^3.2.11", "postcss": "^8.4.31", "preact": "^10.8.0", "preact-router": "^3.2.1", diff --git a/public/images/minecraft_wiki.png b/public/images/minecraft_wiki.png deleted file mode 100644 index 23162c76..00000000 Binary files a/public/images/minecraft_wiki.png and /dev/null differ diff --git a/public/sitemap.txt b/public/sitemap.txt index a60e5676..a31d566d 100644 --- a/public/sitemap.txt +++ b/public/sitemap.txt @@ -31,10 +31,3 @@ https://misode.github.io/report/ https://misode.github.io/upgrader/ https://misode.github.io/changelog/ https://misode.github.io/versions/ -https://misode.github.io/guides/ -https://misode.github.io/guides/adding-custom-structures/ -https://misode.github.io/guides/density-functions/ -https://misode.github.io/guides/feature-order-cycle/ -https://misode.github.io/guides/heightmap-types/ -https://misode.github.io/guides/noise-router/ -https://misode.github.io/guides/placed-features/ diff --git a/src/app/Config.ts b/src/app/Config.ts index cfc60d8f..52ce4255 100644 --- a/src/app/Config.ts +++ b/src/app/Config.ts @@ -25,10 +25,17 @@ export interface ConfigGenerator { maxVersion?: string, } +export interface ConfigLegacyGuide { + id: string, + title: string, + link: string, +} + export interface Config { languages: ConfigLanguage[], versions: ConfigVersion[], generators: ConfigGenerator[], + legacyGuides: ConfigLegacyGuide[], } export default config as Config diff --git a/src/app/components/GuideCard.tsx b/src/app/components/GuideCard.tsx deleted file mode 100644 index 2428406e..00000000 --- a/src/app/components/GuideCard.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useMemo } from 'preact/hooks' -import { getGuide } from '../services/Guides.js' -import { Card } from './Card.jsx' -import { Badge } from './index.js' - -interface Props { - id: string, - minimal?: boolean, - activeTags?: string[], - toggleTag?: (tag: string) => unknown, -} -export function GuideCard({ id, minimal, activeTags, toggleTag }: Props) { - const { title, versions, tags } = useMemo(() => getGuide(id), [id]) - - const onToggleTag = (tag: string) => (e: MouseEvent) => { - if (toggleTag) toggleTag(tag) - e.preventDefault() - e.stopImmediatePropagation() - } - - return -
- {tags?.sort().map(tag => )} -
-
-} diff --git a/src/app/components/index.ts b/src/app/components/index.ts index b202bd81..10e9d2eb 100644 --- a/src/app/components/index.ts +++ b/src/app/components/index.ts @@ -7,18 +7,17 @@ export * from './Card.jsx' export * from './ErrorPanel.js' export * from './FileUpload.js' export * from './Footer.js' -export * from './forms/index.js' -export * from './generator/index.js' export * from './Giscus.js' -export * from './GuideCard.jsx' export * from './Header.js' export * from './Icons.js' export * from './Modal.js' export * from './Octicon.js' -export * from './previews/index.js' -export * from './sounds/index.js' export * from './ToolCard.js' export * from './ToolGroup.jsx' export * from './TreeView.js' -export * from './versions/index.js' export * from './VersionSwitcher.js' +export * from './forms/index.js' +export * from './generator/index.js' +export * from './previews/index.js' +export * from './sounds/index.js' +export * from './versions/index.js' diff --git a/src/app/components/whatsnew/WhatsNewEntry.tsx b/src/app/components/whatsnew/WhatsNewEntry.tsx index 6872bb2b..02b0fe3a 100644 --- a/src/app/components/whatsnew/WhatsNewEntry.tsx +++ b/src/app/components/whatsnew/WhatsNewEntry.tsx @@ -11,6 +11,6 @@ export function WhatsNewEntry({ item }: EntryProps) {

{item.title}

-
+
} diff --git a/src/app/pages/Guide.tsx b/src/app/pages/Guide.tsx index dc519b6f..b510b27d 100644 --- a/src/app/pages/Guide.tsx +++ b/src/app/pages/Guide.tsx @@ -1,201 +1,24 @@ -import hljs from 'highlight.js/lib/core' -import json from 'highlight.js/lib/languages/json' -import { marked } from 'marked' -import { route } from 'preact-router' -import { useCallback, useEffect, useMemo, useState } from 'preact/hooks' import config from '../Config.js' -import { parseFrontMatter, versionContent } from '../Utils.js' -import { Ad, Badge, Btn, Footer, Giscus, Icons, Octicon, VersionSwitcher } from '../components/index.js' -import { useLocale, useTitle, useVersion } from '../contexts/index.js' -import { useActiveTimeout, useAsync, useHash } from '../hooks/index.js' -import type { VersionId } from '../services/index.js' - -const HASH = '' - -hljs.registerLanguage('json', json) - -marked.use({ - highlight: (code, lang) => { - if (lang === '') return undefined - return hljs.highlight(code, { language: lang }).value - }, -}) +import { Footer } from '../components/Footer.jsx' +import { Octicon } from '../components/Octicon.jsx' +import { useTitle } from '../contexts/Title.jsx' interface Props { path?: string id?: string } export function Guide({ id }: Props) { - const { locale } = useLocale() - const { version, changeVersion } = useVersion() - const { changeTitle } = useTitle() - - 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) - changeTitle(data?.title, data?.versions) - return data - }, [content]) - - const allowedVersions = useMemo(() => { - const orderedVersions = config.versions.map(v => v.id) - return (frontMatter?.versions as VersionId[]) - ?.sort((a, b) => orderedVersions.indexOf(b) - orderedVersions.indexOf(a)) - }, [frontMatter?.versions]) - - const guideVersion = useMemo(() => { - if (!allowedVersions) return version - if (allowedVersions.includes(version)) return version - return allowedVersions[0] - }, [version, frontMatter?.versions]) - - const html = useMemo(() => { - if (!content) return undefined - const headings: marked.Tokens.Heading[] = [] - let insertedToc = false - marked.use({ - extensions: [ - { - name: 'styledCode', - level: 'inline', - start(src) { - return src.match(/\b[fsnj]`/)?.index ?? -1 - }, - tokenizer(src) { - const match = src.match(/^([fsnj])`([^`]+)`/) - if (match) { - return { - type: 'styledCode', - raw: match[0], - prefix: match[1], - text: match[2], - } - } - return undefined - }, - renderer(token) { - let content = token.text - let c = { - f: 'hljs-attr', - s: 'hljs-string', - n: 'hljs-number', - }[token.prefix as string] - if (token.prefix === 'j') { - content = hljs.highlight('json', token.text).value - c = 'language-json' - } - return `${content}` - }, - }, - ], - walkTokens(token) { - if (token.type === 'heading') { - headings.push(token) - } - }, - renderer: { - link(href, title, text) { - if (href === null) return text - const title2 = title ? ` title="${title}"` : '' - const target = href?.match(/^https?:\/\//) ? ' target="_blank"' : '' - return `${text}` - }, - heading(text, level, raw, slugger) { - let toc = '' - if (!insertedToc) { - toc = `
    ${headings.filter(t => t.depth === 2).map(t => { - const id = slugger.slug(t.raw.match(/^#+ (.*)/)?.[1] ?? '', { dryrun: true }) - const text = t.text.replaceAll('`', '') - return `
  1. ${text}
  2. ` - }).join('')}
` - insertedToc = true - } - const id = slugger.slug(raw) - const link = `${HASH}` - return `${toc}${link}${text}` - }, - }, - }) - const guide = content.substring(content.indexOf('---', 3) + 3) - const versionedContent = versionContent(guide, guideVersion) - return marked(versionedContent, { version: '1.19' } as any) - }, [guideVersion, content]) - - const [hash, setHash] = useHash() - - const scrollToHeading = useCallback(() => { - if (!html) return - const heading = document.querySelector(`[id=guide-${hash.slice(1)}]`) - if (heading) { - const top = heading.getBoundingClientRect().top + window.scrollY - window.scrollTo({ top: top - 68, behavior: 'smooth' }) - } - }, [html, hash]) - - useEffect(() => { - scrollToHeading() - }, [html === undefined, hash]) - - const clickGuideContent = useCallback((e: MouseEvent) => { - if (!(e.target instanceof HTMLSpanElement)) return - const targetHash = '#' + e.target.id.replace(/^guide-/, '') - changeVersion(version, false, true) - setHash(targetHash) - if (targetHash === hash) { - scrollToHeading() - } - }, [scrollToHeading, hash, version]) - - const [shareActive, shareSuccess] = useActiveTimeout() - - const onShare = useCallback(() => { - const url = `${location.origin}/guides/${id}/?version=${version}` - navigator.clipboard.writeText(url) - shareSuccess() - }, [id, version]) - - const onClickTag = useCallback((tag: string) => { - route(`/guides/?tags=${tag}`) - }, []) - - const [largeWidth] = useState(window.innerWidth > 600) + const guide = config.legacyGuides.find(g => g.id === id) + useTitle(guide?.title) return
-
-
diff --git a/src/app/pages/Guides.tsx b/src/app/pages/Guides.tsx index 85cefc0a..3de0067d 100644 --- a/src/app/pages/Guides.tsx +++ b/src/app/pages/Guides.tsx @@ -1,62 +1,25 @@ -import { useMemo, useState } from 'preact/hooks' -import { Badge, Footer, GuideCard, TextInput, VersionSwitcher } from '../components/index.js' -import { useLocale, useTitle, useVersion } from '../contexts/index.js' -import { useTags } from '../hooks/index.js' -import { getGuides } from '../services/Guides.js' +import { Footer, Octicon } from '../components/index.js' +import config from '../Config.js' interface Props { path?: string } export function Guides({}: Props) { - const { locale } = useLocale() - const { version, changeVersion } = useVersion() - useTitle(locale('title.guides')) - - const [search, setSearch] = useState('') - const [activeTags, toggleTag] = useTags() - - const [versionFilter, setVersionFiler] = useState(false) - - const versionedGuides = useMemo(() => { - if (versionFilter === false) return getGuides() - return getGuides().filter(guide => { - return guide.versions?.includes(version) - }) - }, [version, versionFilter]) - - const filteredGuides = useMemo(() => { - const query = search.split(' ').map(q => q.trim().toLowerCase()).filter(q => q.length > 0) - return versionedGuides.filter(guide => { - if (!activeTags.every(tag => guide.tags?.includes(tag))) { - return false - } - const content = guide.tags?.join(' ') + ' ' + guide.title.toLowerCase() - return query.every(q => { - if (q.startsWith('!')) { - return q.length === 1 || !content.includes(q.slice(1)) - } - return content.includes(q) - }) - }) - }, [versionedGuides, search, activeTags]) - + const guides = config.legacyGuides return
- gen.tags?.includes('worldgen')} /> diff --git a/src/app/services/Guides.ts b/src/app/services/Guides.ts deleted file mode 100644 index 4e4b50c9..00000000 --- a/src/app/services/Guides.ts +++ /dev/null @@ -1,20 +0,0 @@ -export interface Guide { - id: string, - title: string, - versions?: string[], - tags?: string[], -} - -declare var __GUIDES__: Guide[] - -export function getGuides() { - return __GUIDES__ -} - -export function getGuide(id: string): Guide { - const guide = getGuides().find(g => g.id === id) - if (guide === undefined) { - return { id, title: 'Unknown Guide' } - } - return guide -} diff --git a/src/config.json b/src/config.json index 6003edaa..d4a2c905 100644 --- a/src/config.json +++ b/src/config.json @@ -394,5 +394,42 @@ "schema": "immersive_weathering:block_growth", "minVersion": "1.18.2" } + ], + "legacyGuides": [ + { + "id": "adding-custom-structures", + "title": "Adding custom structures", + "link": "Tutorials/Custom_structures" + }, + { + "id": "custom-armor-trims", + "title": "Trim patterns and materials", + "link": "Tutorials/Adding_custom_trims" + }, + { + "id": "density-functions", + "title": "Density function types and their configuration", + "link": "Density_function" + }, + { + "id": "feature-order-cycle", + "title": "How to fix feature order cycles", + "link": "Custom_biome" + }, + { + "id": "heightmap-types", + "title": "The different heightmap types explained", + "link": "Heightmap" + }, + { + "id": "noise-router", + "title": "How terrain is generated using the noise router", + "link": "Noise_router#Final_density" + }, + { + "id": "placed-features", + "title": "Placed features and their configuration", + "link": "Placed_feature" + } ] } diff --git a/src/guides/adding-custom-structures.md b/src/guides/adding-custom-structures.md deleted file mode 100644 index 14e5fc20..00000000 --- a/src/guides/adding-custom-structures.md +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Adding custom structures -versions: - - '1.18.2' - - '1.19' -tags: - - worldgen - - structures ---- - -This guide will showcase how to create a data pack that adds a custom structure to the world. There is also a [data pack download]({#[1.18.2] https://gist.github.com/misode/45559d34627755ecaa52497daea83544/raw/8ece848257e6ce17769ca17eccdf89b5889afbe2/tall-towers-1.18.2.zip #}{#[1.19] https://gist.github.com/misode/45559d34627755ecaa52497daea83544/raw/b7d7c44a132641d308cbdc93ce4cf061759d15c5/tall-towers-1.19.zip #}) of this complete example. - -> **Always leave the world and rejoin to apply the new changes!** - -## Pack.mcmeta -Like every data pack, we need a `pack.mcmeta`. In this version, the pack format is {#pack_format#}. -```json -{ - "pack": { - "pack_format": {#pack_format#}, - "description": "A tall tower" - } -} -``` - -## The structure set -A structure set is where the placement starts. It defines where in the world the structure should be placed, and how rare it is. It takes a weighted list of different structures, allowing structure variants (for example the [vanilla nether](/worldgen/structure-set/?preset=nether_complexes&version={#version#}) has a structure set with both the bastion and fortress). - -**`data/example/worldgen/structure_set/tall_towers.json`** -```json -{ - "structures": [ - { - "structure": "example:tall_tower", - "weight": 1 - } - ], - "placement": { - "type": "minecraft:random_spread", - "spacing": 5, - "separation": 2, - "salt": 1646207470 - } -} -``` -Structure sets are made up of two parts: -* f`structures`: A weighted list of configured structure features [(see next step)](#the{#[1.18.2] -configured #}-structure). -* f`placement`: The structure placement - * f`type`: Either s`random_spread` or s`concentric_rings`. The latter is only used by strongholds in vanilla, so we'll focus on s`random_spread` - * f`spacing`: Roughly the average distance in chunks between two structures in this set. - * f`separation`: The minimum distance in chunks. Needs to be smaller than spacing. - * f`salt`: A random number that is combined with the world seed. Always use a different random number for different structures, otherwise they will end up being placed in the same spot! - -When using the s`random_spread` placement type, it generates structures grid-based. Here's an illustration of the above example with `spacing = 5`, `separation = 2`. There will be one structure attempt in each 5x5 chunk grid, and only at `X` a structure can spawn. -``` -............. -..XXX..XXX..X -..XXX..XXX..X -..XXX..XXX..X -............. -............. -..XXX..XXX..X -..XXX..XXX..X -..XXX..XXX..X -``` - -## The {#[1.18.2] configured structure #}{#[1.19] structure #} -The {#[1.18.2] configured structure (feature) #}{#[1.19] structure #} is the ID you will be able to reference in `/locate`. - -**`data/example/worldgen/{#[1.18.2] configured_structure_feature #}{#[1.19] structure #}/tall_tower.json`** -```json -{#[1.18.2] -{ - "type": "minecraft:village", - "config": { - "start_pool": "example:tall_tower", - "size": 1 - }, - "biomes": "#minecraft:has_structure/mineshaft", - "adapt_noise": true, - "spawn_overrides": {} -} -#}{#[1.19] -{ - "type": "minecraft:jigsaw", - "biomes": "#minecraft:has_structure/mineshaft", - "step": "surface_structures", - "spawn_overrides": {}, - "terrain_adaptation": "beard_thin", - "start_pool": "example:tall_tower", - "size": 1, - "start_height": { - "absolute": 0 - }, - "project_start_to_heightmap": "WORLD_SURFACE_WG", - "max_distance_from_center": 80, - "use_expansion_hack": false -} -#} -``` -Let's go over all the fields. -{#[1.18.2] -* f`type`: This is the structure feature type. When making custom structures, you almost always want to set this to s`village` or s`bastion_remnant`. There is one important difference between the two: using s`village` will spawn the structure on the surface, while s`bastion_remnant` will always spawn the structure at Y=33. -* f`config`: - * f`start_pool`: This is a reference to the template pool [(see next step)](#the-template-pool). - * f`size`: This is a number between 1 and 7. This is important if your structure uses jigsaw. In this simple example, we'll leave it at 1. -* f`biomes`: This controls in which biomes this structure is allowed to generate. You can give it any biome tag, a list of biomes, or a single biome. For easy testing we'll set it to every biome with mineshafts. -* f`adapt_noise`: When true, it will add extra terrain below each structure piece. -* f`spawn_overrides`: This field allows you to override mob spawning inside the structure bounding boxes. This is outside the scope of this guide, but you could look at the [vanilla monument](/worldgen/structure-feature/?preset=monument&version={#version#}) structure feature as a reference. -#}{#[1.19] -* f`type`: This is the structure type. When making custom structures, you almost always want to set this to s`jigsaw`. -* f`biomes`: This controls in which biomes this structure is allowed to generate. You can give it any biome tag, a list of biomes, or a single biome. For easy testing we'll set it to every biome with mineshafts. -* f`step`: The generation step to place the features in. This matches the steps in a biome's `feature` list. Possible values: s`raw_generation`, s`lakes`, s`local_modifications`, s`underground_structures`, s`surface_structures`, s`strongholds`, s`underground_ores`, s`underground_decoration`, s`fluid_springs`, s`vegetal_decoration`, and s`top_layer_modification`. -* f`terrain_adaptation`: Controls how the structure will affect the terrain. It has 4 options: - * s`none`: (default) No effect on the terrain. - * s`beard_thin`: Adds terrain below the structure and removes inside the structure. This is what villages use. - * s`beard_box`: Stronger version of s`beard_thin`. This is what ancient cities use. - * s`bury`: Adds terrain completely around the structure. This is what strongholds use. -* f`spawn_overrides`: This field allows you to override mob spawning inside the structure bounding boxes. This is outside the scope of this guide, but you could look at the [vanilla monument](/worldgen/structure/?preset=monument&version={#version#}) structure feature as a reference. -* f`start_pool`: This is a reference to the template pool [(see next step)](#the-template-pool). -* f`size`: This is a number between 1 and 7. This is important if your structure uses jigsaw. In this simple example, we'll leave it at 1. -* f`start_height`: A height provider specifying at which height the structure should spawn. The example uses the constant shorthand so it just specifies a vertical anchor. If used together with f`project_start_to_heightmap`, will offset the height relative to the heightmap. -* f`project_start_to_heightmap`: An optional [heightmap type](/guides/heightmap-types/). Possible values: s`WORLD_SURFACE_WG`, s`WORLD_SURFACE`, s`OCEAN_FLOOR_WG`, s`OCEAN_FLOOR`, s`MOTION_BLOCKING`, and s`MOTION_BLOCKING_NO_LEAVES`. -* f`max_distance_from_center`: Value between 1 and 128. The maximum distance that a jigsaw can branch out. -* f`use_expansion_hack`: You should always set this to false. Vanilla villages set this to true to fix an issue with their streets. -#} - -## The template pool -The template pool defines how to build up your structure. Since we're not using jigsaw, this is quite straight forward: we want to place a single NBT structure. - -**`data/example/worldgen/template_pool/tall_tower.json`** -```json -{ - "name": "example:tall_tower", - "fallback": "minecraft:empty", - "elements": [ - { - "weight": 1, - "element": { - "element_type": "minecraft:single_pool_element", - "location": "example:stone_tall_tower", - "projection": "rigid", - "processors": "minecraft:empty" - } - } - ] -} -``` -Again, let's go over the fields: -* f`name`: For some reason, the game needs the name of this template pool. Just set this to the ID of the template pool. -* f`fallback`: Used in jigsaw structures, but we can simply use s`minecraft:empty`. -* f`elements`: A weighted list of pool elements to choose from. You can add multiple elements here if your structure has different starting structure files. For example in vanilla a plains village has different town center variants. - * f`element_type`: The type of this element. One of s`empty_pool_element` (placing nothing), s`feature_pool_element` (placing a placed feature), s`legacy_single_pool_element`, s`list_pool_element`, and s`single_pool_element` (placing a structure). - * f`location`: The path to the structure NBT file. [(see next step)](#the-structure-nbt). - * f`projection`: Either s`rigid` or s`terrain_matching`. Use the latter if you want the structure to match the terrain, just like village paths do. - * f`processors`: If you want to run any processor lists, this is quite complicated so again we'll skip this for now and set it to s`minecraft:empty`. - -## The structure NBT -Creating the structure NBT file is entirely up to you. In this example I'm going to use a tower structure from [Gamemode 4](https://gm4.co/modules/tower-structures). - -**`data/example/structures/stone_tall_tower.nbt`** - -(binary NBT file) [Download the structure from this example](https://gist.github.com/misode/45559d34627755ecaa52497daea83544/raw/8b41b3e273210e0455e4bd4fa97b5504b65aff2c/stone_tall_tower.nbt) - -## Result -![stone tower close-up](https://user-images.githubusercontent.com/17352009/154780743-c704d23b-9343-4167-8273-acc7a380d037.png) -![a bunch of towers in a forest](https://user-images.githubusercontent.com/17352009/154780794-1585c927-682c-4b26-b1cc-f9132fffc24a.png) diff --git a/src/guides/custom-armor-trims.md b/src/guides/custom-armor-trims.md deleted file mode 100644 index 11ab973e..00000000 --- a/src/guides/custom-armor-trims.md +++ /dev/null @@ -1,446 +0,0 @@ ---- -title: Trim patterns and materials -versions: - - '1.19.4' ---- - -The 23w04a snapshot added armor trims which can be used to customise the texture of items. - -The complete data packs and resource packs of these examples can be found in the [trim-examples repository](https://github.com/misode/trim-examples). - -> **For trim patterns and materials to work you need to enable the `update_1_20` experimental data pack!** - -## Adding a custom trim pattern -In this example we're going to add a new "Stripes" pattern that works with all the vanilla armor types and colors. - -![stripes_trim_pattern](https://user-images.githubusercontent.com/17352009/214461348-68abfe9b-554c-4615-97d6-06df2de28c48.png) - -### Data pack part -Let's start with the central file in the `trim_pattern` folder in the data pack. - -> **Changes to this file won't be applied when running `/reload`. Always leave the world and rejoin to apply the new changes!** - -**`data/example/trim_pattern/stripes.json`** -```json -{ - "asset_id": "example:stripes", - "description": { - "translate": "trim_pattern.example.stripes" - }, - "template_item": "minecraft:stick" -} -``` -* f`asset_id`: A resource location which will be used in the resource pack. -* f`description`: A text component shown in the item tooltip. -* f`template_item`: The item representing this pattern. - -The second and final piece required in the data pack is the recipe. - -**`data/example/recipes/stripes_armor_trim.json`** -```json -{ - "type": "minecraft:smithing_trim", - "addition": { - "tag": "minecraft:trim_materials" - }, - "base": { - "tag": "minecraft:trimmable_armor" - }, - "template": { - "item": "minecraft:stick" - } -} -``` - -### Resource pack part -We'll quickly add a language file used by the item tooltip: - -**`assets/example/lang/en_us.json`** -```json -{ - "trim_pattern.example.stripes": "Stripes Armor Trim" -} -``` - -And now for the complicated bit: adding the texture permutations for the different colors and armor types. This is done by appending the `minecraft:armor_trims` atlas file. - -**`assets/minecraft/atlases/armor_trims.json`** -```json -{ - "sources": [ - { - "type": "paletted_permutations", - "textures": [ - "example:trims/models/armor/stripes", - "example:trims/models/armor/stripes_leggings" - ], - "palette_key": "trims/color_palettes/trim_palette", - "permutations": { - "quartz": "trims/color_palettes/quartz", - "iron": "trims/color_palettes/iron", - "gold": "trims/color_palettes/gold", - "diamond": "trims/color_palettes/diamond", - "netherite": "trims/color_palettes/netherite", - "redstone": "trims/color_palettes/redstone", - "copper": "trims/color_palettes/copper", - "emerald": "trims/color_palettes/emerald", - "lapis": "trims/color_palettes/lapis", - "amethyst": "trims/color_palettes/amethyst" - } - } - ] -} -``` -* f`sources`: The list of sprite sources that will be merged with the vanilla atlas. - * f`type`: We use the s`paletted_permutations` type here. - * f`textures`: A list of grayscale trim pattern textures that we want to generate permutations of with the colors defined below. - * f`palette_key`: The same trim palette key as vanilla. - * f`permutations`: The same color palettes as vanilla. - -It's important to use the same format in the f`textures` list. When rendering armor, the game will use the f`asset_id` from the data pack and insert s`trims/models/armor/` to look for the texture. - -The remaining two files are the texture files we specified in the atlas. You can download them here and put them in **`assets/example/textures/trims/models/armor/`**. -* [`stripes_leggings.png`](https://github.com/misode/trim-examples/raw/main/custom_trim_pattern/custom_trim_pattern_rp/assets/example/textures/trims/models/armor/stripes_leggings.png) -* [`stripes.png`](https://github.com/misode/trim-examples/raw/main/custom_trim_pattern/custom_trim_pattern_rp/assets/example/textures/trims/models/armor/stripes.png) - -## Adding a custom trim material -In this second example we're adding a new "Ender" material that works with all the vanilla armor types and colors. - -![ender_trim_material](https://user-images.githubusercontent.com/17352009/214466110-f779a329-aa56-485a-bb32-7b28fda51f5f.png) - -### Data pack part -Let's start now with the `trim_material`. - -**`data/example/trim_material/ender.json`** -```json -{ - "asset_name": "ender", - "description": { - "color": "#258474", - "translate": "trim_material.example.ender" - }, - "ingredient": "minecraft:ender_pearl", - "item_model_index": 0.85 -} -``` -* f`asset_name`: A string which will be used in the resource pack. -* f`description`: A text component shown in the item tooltip. -* f`ingredient`: The item used in the smithing table for this material. -* f`item_model_index`: A "random" number that we will reference in the predicates of the item models. -* f`incompatible_armor_material` (optional): If this material is incompatible with an armor material. Possible values: `leather`, `chainmail`, `iron`, `gold`, `diamond`, `turtle`, or `netherite`. - -We need to add the ender pearl to the `#minecraft:trim_materials` item tag. This makes our material usable in the smithing recipes. - -**`data/minecraft/tags/items/trim_materials.json`** -```json -{ - "values": [ - "minecraft:ender_pearl" - ] -} -``` - -### Resource pack part -Now to finish off with the resource pack. Let's quickly add a language file used by the item tooltip: - -**`assets/example/lang/en_us.json`** -```json -{ - "trim_material.example.ender": "Ender Material" -} -``` - -For trim materials, we need to append two atlas files: one for the armor entity rendering and one for the inventory item models. - -**`assets/minecraft/atlases/armor_trims.json`** -```json -{ - "sources": [ - { - "type": "paletted_permutations", - "textures": [ - "trims/models/armor/coast", - "trims/models/armor/coast_leggings", - "trims/models/armor/sentry", - "trims/models/armor/sentry_leggings", - "trims/models/armor/dune", - "trims/models/armor/dune_leggings", - "trims/models/armor/wild", - "trims/models/armor/wild_leggings", - "trims/models/armor/ward", - "trims/models/armor/ward_leggings", - "trims/models/armor/eye", - "trims/models/armor/eye_leggings", - "trims/models/armor/vex", - "trims/models/armor/vex_leggings", - "trims/models/armor/tide", - "trims/models/armor/tide_leggings", - "trims/models/armor/snout", - "trims/models/armor/snout_leggings", - "trims/models/armor/rib", - "trims/models/armor/rib_leggings", - "trims/models/armor/spire", - "trims/models/armor/spire_leggings" - ], - "palette_key": "trims/color_palettes/trim_palette", - "permutations": { - "ender": "example:trims/color_palettes/ender" - } - } - ] -} -``` -**`assets/minecraft/atlases/blocks.json`** -```json -{ - "sources": [ - { - "type": "paletted_permutations", - "textures": [ - "trims/items/leggings_trim", - "trims/items/chestplate_trim", - "trims/items/helmet_trim", - "trims/items/boots_trim" - ], - "palette_key": "trims/color_palettes/trim_palette", - "permutations": { - "ender": "example:trims/color_palettes/ender" - } - } - ] -} -``` -* f`sources`: The list of sprite sources that will be merged with the vanilla atlas. - * f`type`: We use the s`paletted_permutations` type here. - * f`textures`: The same list of textures as vanilla. - * f`palette_key`: The same trim palette key as vanilla. - * f`permutations`: Our custom materials that we want to add permutations for. Our key f`ender` should match what we had for f`asset_name` in the data pack. - -These atlas files reference a color palette which we need to create. Since we use the vanilla palette key, the image has a width of 8 and a height of 1. You can download it here: [`ender.png`](https://github.com/misode/trim-examples/raw/main/custom_trim_material/custom_trim_material_rp/assets/example/textures/trims/color_palettes/ender.png). Put it in **`assets/example/textures/trims/color_palettes/ender.png`**. - -*(Don't save the image below, which has been scaled up)* -![ender_color_palette](https://user-images.githubusercontent.com/17352009/214469452-f1d0d033-8597-4ead-b929-3061607ece52.png) - -Finally, the most time consuming step is to add the item model predicate to all the possible items. In this example I only added it for the iron chestplate. - -**`assets/minecraft/models/item/iron_chestplate.json`** -```json -{ - "parent": "minecraft:item/generated", - "overrides": [ - { - "model": "minecraft:item/iron_chestplate_quartz_trim", - "predicate": { - "trim_type": 0.1 - } - }, - { - "model": "minecraft:item/iron_chestplate_netherite_trim", - "predicate": { - "trim_type": 0.3 - } - }, - { - "model": "minecraft:item/iron_chestplate_redstone_trim", - "predicate": { - "trim_type": 0.4 - } - }, - { - "model": "minecraft:item/iron_chestplate_copper_trim", - "predicate": { - "trim_type": 0.5 - } - }, - { - "model": "minecraft:item/iron_chestplate_gold_trim", - "predicate": { - "trim_type": 0.6 - } - }, - { - "model": "minecraft:item/iron_chestplate_emerald_trim", - "predicate": { - "trim_type": 0.7 - } - }, - { - "model": "minecraft:item/iron_chestplate_diamond_trim", - "predicate": { - "trim_type": 0.8 - } - }, - { - "model": "example:item/iron_chestplate_ender_trim", - "predicate": { - "trim_type": 0.85 - } - }, - { - "model": "minecraft:item/iron_chestplate_lapis_trim", - "predicate": { - "trim_type": 0.9 - } - }, - { - "model": "minecraft:item/iron_chestplate_amethyst_trim", - "predicate": { - "trim_type": 1.0 - } - } - ], - "textures": { - "layer0": "minecraft:item/iron_chestplate" - } -} -``` -This is mostly the vanilla iron chestplate item model, but we added an override with the j`"trim_type": 0.85` predicate for our custom material. The order is important here! - -This references another item model file, which we need to create. - -**`assets/example/models/item/iron_chestplate_ender_trim.json`** -```json -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "minecraft:item/iron_chestplate", - "layer1": "minecraft:trims/items/chestplate_trim_ender" - } -} -``` -This item model references the s`trims/items/chestplate_trim_ender` sprite that was generated in the `blocks.json` atlas. - -Since we haven't added the override for all the other armor types, they will default to the previous f`trim_type`, in our case n`0.8`, which is diamonds. - -## Adding a custom trimmable item -In this example we're going to add the `iron_axe` as a trimmable item. Since this is not an armor item, we only need to worry about the item model. The trim pattern used will have no effect on the texture, only the trim material can be used in the model overrides. - -![trimmable_axe_item](https://user-images.githubusercontent.com/17352009/214481089-dcaa5eee-77f5-4ad7-a35f-3cb5fb9b7565.png) - -### Data pack part -The only change in the data pack is adding the item to the `#minecraft:trimmable_armor` item tag. - -**`data/minecraft/tags/items/trimmable_armor.json`** -```json -{ - "values": [ - "minecraft:iron_axe" - ] -} -``` - -### Resource pack part -We start in the resource pack by customizing the iron axe item model. - -**`assets/minecraft/models/item/iron_axe.json`** -```json -{ - "parent": "minecraft:item/generated", - "overrides": [ - { - "model": "example:item/iron_axe_quartz_trim", - "predicate": { - "trim_type": 0.1 - } - }, - { - "model": "example:item/iron_axe_netherite_trim", - "predicate": { - "trim_type": 0.3 - } - }, - { - "model": "example:item/iron_axe_redstone_trim", - "predicate": { - "trim_type": 0.4 - } - }, - { - "model": "example:item/iron_axe_copper_trim", - "predicate": { - "trim_type": 0.5 - } - }, - { - "model": "example:item/iron_axe_gold_trim", - "predicate": { - "trim_type": 0.6 - } - }, - { - "model": "example:item/iron_axe_emerald_trim", - "predicate": { - "trim_type": 0.7 - } - }, - { - "model": "example:item/iron_axe_diamond_trim", - "predicate": { - "trim_type": 0.8 - } - }, - { - "model": "example:item/iron_axe_lapis_trim", - "predicate": { - "trim_type": 0.9 - } - }, - { - "model": "example:item/iron_axe_amethyst_trim", - "predicate": { - "trim_type": 1.0 - } - } - ], - "textures": { - "layer0": "minecraft:item/iron_axe" - } -} -``` -This lists all the vanilla trim materials and overrides the model with our custom item models. Each of those looks like this: - -**`assets/example/models/item/iron_axe_amethyst_trim.json`** -```json -{ - "parent": "minecraft:item/handheld", - "textures": { - "layer0": "minecraft:item/iron_axe", - "layer1": "example:trims/items/axe_trim_amethyst" - } -} -``` - -> **Create this file for each of the 10 materials!** - -The above item models reference an `axe_trim_amethyst` texture. To make this work we need to add these permutations for the axe to the `blocks.json` atlas. - -**`assets/minecraft/atlases/blocks.json`** -```json -{ - "sources": [ - { - "type": "paletted_permutations", - "textures": [ - "example:trims/items/axe_trim" - ], - "palette_key": "trims/color_palettes/trim_palette", - "permutations": { - "quartz": "trims/color_palettes/quartz", - "iron": "trims/color_palettes/iron", - "gold": "trims/color_palettes/gold", - "diamond": "trims/color_palettes/diamond", - "netherite": "trims/color_palettes/netherite", - "redstone": "trims/color_palettes/redstone", - "copper": "trims/color_palettes/copper", - "emerald": "trims/color_palettes/emerald", - "lapis": "trims/color_palettes/lapis", - "amethyst": "trims/color_palettes/amethyst" - } - } - ] -} -``` -This references the s`axe_trim` texture, which is a mask for which pixels to color with the color palette. You can download this texture here: [`axe_trim.png`](https://raw.githubusercontent.com/misode/trim-examples/main/custom_trimmable_item/custom_trimmable_item_rp/assets/example/textures/trims/items/axe_trim.png). Put it in **`assets/example/textures/trims/items/axe_trim.png`**. - -## Download -A reminder that the complete data packs and resource packs of these examples can be found in the [trim-examples repository](https://github.com/misode/trim-examples). diff --git a/src/guides/density-functions.md b/src/guides/density-functions.md deleted file mode 100644 index 46b6fb85..00000000 --- a/src/guides/density-functions.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -title: Density function types and their configuration -versions: - - '1.18.2' - - '1.19' -tags: - - worldgen - - noise - - density ---- - -[Density functions](/worldgen/density-function/) are used by the dimension generator to generate the terrain. They make up mathematical expressions that decide whether or not a block should be solid terrain. - -## Density functions -There are 3 ways to specify a density function. The first is simply as a constant number. The density function will always return that value -```json -0.58 -``` - -Another option is to reference a density function file. Vanilla has some builtin density functions, but you can create your own density functions in the `worldgen/density_function` folder. -```json -"minecraft:overworld/base_3d_noise" -``` - -All the other density function types are defined as an object with a f`type` field and optionally more fields. -```json -{ - "type": "minecraft:noise", - "noise": "minecraft:cave_entrance", - "xz_scale": 0.75, - "y_scale": 0.5 -} -``` - -## Types - -### `abs` -Calculates the absolute value of another density function. -* f`argument`: The input density function - -### `add` -Adds two density functions together. -* f`argument1`: The first density function -* f`argument2`: The second density function - -### `beardifier` -Adds beards for structures ({#[1.18.2] see the f`adapt_noise` field in [structures](/worldgen/structure-feature/) #}{#[1.19] see the f`terrain_adaptation` field in [structures](/worldgen/structure/) #}). - -*This density function has no extra fields* - -### `blend_alpha` - -*This density function has no extra fields* - -### `blend_density` -* f`argument`: The input density function - -### `blend_offset` - -*This density function has no extra fields* - -### `cache_2d` -Only computes the input density once for each column, at Y=0 -* f`argument`: The input density function - -### `cache_all_in_cell` -Used in combination with [`interpolated`](#interpolated). -* f`argument`: The input density function - -### `cache_once` -If this density function is referenced twice, it is only computed once per block position. -* f`argument`: The input density function - -### `clamp` -Clamps the input between two values. -* f`input`: The input density function -* f`min`: The lower bound -* f`max`: The upper bound - -### `constant` -A constant value. j`{"type": "constant", "argument": 2}` is equivalent to n`2`. -* f`argument`: The constant number - -### `cube` -Cubes the input. (`x^3`) -* f`argument`: The input density function - -### `end_islands` - -*This density function has no extra fields* - -### `flat_cache` -Similar to [`cache_2d`](#cache_2d) in that it only computes the input once for each column, but now at the first Y value that is requested. - -### `half_negative` -If the input is negative, returns half of the input. Otherwise returns the input. (`x < 0 ? x/2 : x`) -* f`argument`: The input density function - -### `interpolated` -Computes the input density at each of the 8 corners of a cell and interpolates between them. The size of a cell if determined by `size_horizontal * 4` and `size_vertical * 4`. -* f`argument`: The input density function - -### `max` -Returns the maximum of two density functions. -* f`argument1`: The first density function -* f`argument2`: The second density function - -### `min` -Returns the minimum of two density functions. -* f`argument1`: The first density function -* f`argument2`: The second density function - -### `mul` -Multiplies two density functions. -* f`argument1`: The first density function -* f`argument2`: The second density function - -### `noise` -The noise density function samples a [noise](/worldgen/noise/). -* f`noise`: A reference to a `worldgen/noise` file -* f`xz_scale`: Scales the X and Z inputs before sampling -* f`y_scale`: Scales the Y input before sampling - -### `old_blended_noise` -Uses a different kind of noise than [`noise`](#noise). -* f`xz_scale` -* f`y_scale` -* f`xz_factor` -* f`y_factor` -* f`smear_scale_multiplier` - -### `quarter_negative` -If the input is negative, returns a quarter of the input. Otherwise returns the input. (`x < 0 ? x/4 : x`) -* f`argument`: The input density function - -### `range_choice` -Computes the input value, and depending on that result returns one of two other density functions. Basically an if-then-else statement. -* f`input`: The input density function -* f`min_inclusive`: The lower bound of the range -* f`max_exclusive`: The upper bound of the range -* f`when_in_range`: Density function that will be returned when the input is inside the range -* f`when_out_of_range`: Density function that will be returned When the input is outside the range - -### `shift` -Samples a noise at `(x/4, y/4, z/4)`. -* f`argument`: A reference to a `worldgen/noise` file - -### `shift_a` -Samples a noise at `(x/4, 0, z/4)`. -* f`argument`: A reference to a `worldgen/noise` file - -### `shift_b` -Samples a noise at `(z/4, x/4, 0)`. -* f`argument`: A reference to a `worldgen/noise` file - -### `shifted_noise` -Similar to [`noise`](#noise), but first shifts the input coordinates. -* f`noise`: A reference to a `worldgen/noise` file -* f`xz_scale`: Scales the X and Z inputs before sampling -* f`y_scale`: Scales the Y input before sampling -* f`shift_x`: Density function used to offset the X input -* f`shift_y`: Density function used to offset the Y input -* f`shift_z`: Density function used to offset the Z input - -### `spline` -Computes a spline. More information about splines will follow in a future guide. -* f`spline`: The spline, can be either a number or an object: - * f`coordinate`: The density function that will be used for the locations - * f`points`: List of points of the cubic spline, cannot be empty - * f`location`: Input value - * f`value`: Output value, can be either a number or a spline object - * f`derivative`: The slope at this point -{#[1.18.2] -* f`min_value`: The minimum output value of the spline -* f`max_value`: The maximum output value of the spline -#} - -### `square` -Squares the input. (`x^2`) -* f`argument`: The input density function - -### `squeeze` -First clamps the input between `-1` and `1`, then transforms it using `x/2 - x*x*x/24`. -* f`argument`: The input density function - -{#[1.18.2] -### `terrain_shaper_spline` -Computes a terrain shaper spline from the noise settings. -* f`spline`: The terrain shaper spline to use. One of s`offset`, s`factor`, or s`jaggedness` -* f`min_value`: The minimum output value of the spline -* f`max_value`: The maximum output value of the spline -* f`continentalness`: The density function to use for the s`continents` spline coordinate -* f`erosion`: The density function to use for the s`erosion` spline coordinate -* f`weirdness`: The density function to use for the s`weirdness` spline coordinate -#} - -### `weird_scaled_sampler` -* f`rarity_value_mapper`: One of s`type_1` or s`type_2` -* f`noise`: A reference to a `worldgen/noise` file -* f`input`: The input density function - -### `y_clamped_gradient` -Returns the Y position after mapping it to a range. -* f`from_y` -* f`to_y` -* f`from_value`: The value to map f`from_y` to -* f`to_value`: The value to map f`to_y` to diff --git a/src/guides/feature-order-cycle.md b/src/guides/feature-order-cycle.md deleted file mode 100644 index 564c1862..00000000 --- a/src/guides/feature-order-cycle.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -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](/guides/placed-features/) 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, s`blue_tree` is before s`rocks`; while in the `example:plains` biome, s`rocks` is before s`blue_tree`. - -## How to fix it -The rule is that for each step in f`"features"`, all feature IDs 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/guides/heightmap-types.md b/src/guides/heightmap-types.md deleted file mode 100644 index ede31ed5..00000000 --- a/src/guides/heightmap-types.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: The different heightmap types explained -versions: - - '1.16' - - '1.17' - - '1.18' - - '1.18.2' - - '1.19' -tags: - - worldgen ---- - -Heightmaps are essentially a cache that store the height of the terrain for each block column in a chunk. - -They are computed by starting at the top of the world and iterating downwards, for each block checking if a condition still matches. Let's go over each type to see how they work. - -## `WORLD_SURFACE` -The world surface heightmap is the simplest one. It checks whether the block is air or not. This only matches `air`, `void_air` and `cave_air`. - -## `WORLD_SURFACE_WG` -The worldgen variant of `WORLD_SURFACE`. Works exactly the same, but is updated during worldgen and is discarded after worldgen is finished. - -## `OCEAN_FLOOR` -The ocean floor heightmap checks that the block has no collision box. This means it will pass through air, water, lava, bubble columns, portals, most plants, fire, cobwebs, powder snow, and many more blocks. An exception are carpets, which are seen as having no collision box to this heightmap. - -## `OCEAN_FLOOR_WG` -The worldgen variant of `OCEAN_FLOOR`. Works exactly the same, but is updated during worldgen and is discarded after worldgen is finished. - -## `MOTION_BLOCKING` -The motion blocking heightmap is similar to `OCEAN_FLOOR` that checks that the block has no collision box. The difference is that it also checks that there is no fluid in the block. - -## `MOTION_BLOCKING_NO_LEAVES` -Similar to `MOTION_BLOCKING` but as the name suggests, this ignores leaves. The heightmap will be set to the ground next to trees even if leaves are above it. diff --git a/src/guides/noise-router.md b/src/guides/noise-router.md deleted file mode 100644 index 483ca886..00000000 --- a/src/guides/noise-router.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: How terrain is generated using the noise router -versions: - - '1.18.2' - - '1.19' -tags: - - worldgen - - noise - - density ---- - -The noise router is a piece of configuration in [noise settings](/worldgen/noise-settings/). It's a collection of [density functions](/guides/density-functions/), some used for the biome layout, aquifers, or ore veins. - -## Noise router -The different parts of the noise router and their uses. -|Density function|Usage| -|---|---| -|f`barrier`
f`fluid_level_floodedness`
f`fluid_level_spread`
f`lava`|Aquifers -|f`vein_toggle`
f`vein_ridged`
f`vein_gap`|Ore veins| -|f`temperature`
f`vegetation`
f`continents`
f`erosion`
f`ridges`
f`depth`|Biome climate parameters| -|f`initial_density_without_jaggedness`|Approximate surface height| -|f`final_density`|Terrain| - -## Final density -The density function that decides the terrain is f`final_density`. This density function will be computed for every block position. If it returns a value greater than n`0` the default block will be placed, otherwise either air or the default fluid will be placed. - -With this information we can make the most basic noise router, one where every density function is set to n`0`. As predicted, this will result in a void world. Similarly, setting j`"final_density": 1` will result in a world completely filled with stone. - -**`data/minecraft/worldgen/noise_settings/overworld.json`** -```json -{ - "sea_level": 63, - "disable_mob_generation": false, - "aquifers_enabled": false, - "ore_veins_enabled": false, - "legacy_random_source": false, - "default_block": { - "Name": "minecraft:stone" - }, - "default_fluid": { - "Name": "minecraft:water", - "Properties": { - "level": "0" - } - }, - "noise": { - "min_y": -64, - "height": 384, - "size_horizontal": 2, - "size_vertical": 2{#[1.18.2] , - "sampling": { - "xz_scale": 1, - "y_scale": 1, - "xz_factor": 80, - "y_factor": 160 - }, - "bottom_slide": { - "target": 0, - "size": 0, - "offset": 0 - }, - "top_slide": { - "target": 0, - "size": 0, - "offset": 0 - }, - "terrain_shaper": { - "offset": 0, - "factor": 0, - "jaggedness": 0 - } #} - }, - "noise_router": { - "barrier": 0, - "fluid_level_floodedness": 0, - "fluid_level_spread": 0, - "lava": 0, - "temperature": 0, - "vegetation": 0, - "continents": 0, - "erosion": 0, - "depth": 0, - "ridges": 0, - "initial_density_without_jaggedness": 0, - "final_density": 0, - "vein_toggle": 0, - "vein_ridged": 0, - "vein_gap": 0 - }, - "spawn_target": [], - "surface_rule": { - "type": "minecraft:sequence", - "sequence": [] - } -} -``` - -## Flat world -Let's continue with a simple density function that creates a flat world at Y=n`128`. Instead of n`0`, we now have this as the f`final_density`: -```json -{ - "type": "minecraft:y_clamped_gradient", - "from_y": -64, - "to_y": 320, - "from_value": 1, - "to_value": -1 -} -``` -The image below illustrates how s`y_clamped_gradient` works. In this example positions at Y=n`-64` will get a density of n`1` and positions at Y=n`320` will get a density of n`-1`. - -![illustration of Y coordinates getting mapped the [-1, 1] range](https://user-images.githubusercontent.com/17352009/184545378-5e00870e-35d5-4b9c-9336-269571f6c194.png) - -And the result looks like this: - -![a flat world](https://user-images.githubusercontent.com/17352009/170412400-52b1db55-3daf-48a9-b436-22119fe9ba06.png) - - -## First noise -To bring some variety to the world we need noise. We can improve the existing density function by adding a noise to it, like this: -```json -{ - "type": "minecraft:add", - "argument1": { - "type": "minecraft:y_clamped_gradient", - "from_y": -64, - "to_y": 320, - "from_value": 1, - "to_value": -1 - }, - "argument2": { - "type": "minecraft:noise", - "noise": "minecraft:gravel", - "xz_scale": 2, - "y_scale": 0 - } -} -``` - -We get the following result. The height of the terrain is based on a noise that varies along the X and Z coordinates. - -![terrain with random elevations](https://user-images.githubusercontent.com/17352009/170411319-2a797950-95c4-4b90-b1a5-ff2ae4ae66ef.png) - -To make the terrain smoother, we can stretch the noise by altering the f`xz_scale` field. This is the result with j`"xz_scale": 0.5`: - -![terrain with smooth hills](https://user-images.githubusercontent.com/17352009/170411382-6a84f017-5c71-4e63-b90d-c17104ef57b1.png) - -To get overhangs, the noise also needs to vary along the Y coordinate. The following is with j`"xz_scale": 1` and j`"y_scale": 1`. - -![](https://user-images.githubusercontent.com/17352009/170412018-757999be-4595-4be8-9943-a3d3395a2add.png) - -## Splines -🚧 *to be continued* 🚧 diff --git a/src/guides/placed-features.md b/src/guides/placed-features.md deleted file mode 100644 index c6786be3..00000000 --- a/src/guides/placed-features.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: Placed features and their configuration -versions: - - '1.18' - - '1.18.2' - - '1.19' -tags: - - worldgen - - features ---- - -[Placed features](/worldgen/placed-feature/) are a combination of a [configured feature](/worldgen/feature/) and a list of placement modifiers. They decide the placement of a feature in biomes. This includes position, rarity, count, filters, and more. - -## Placed features -Placed features are referenced in the f`features` list of biomes. They may also be referenced in some configured features types, such as in the `vegetation_patch` feature. - -Let's look at an example placed feature: -```json -{ - "feature": "minecraft:monster_room", - "placement": [ - { - "type": "minecraft:count", - "count": 2 - } - ] -} -``` -There are two fields in the placed feature configuration: -* f`feature`: The configured feature that the placed feature is going to place. Can either be referencing a configured feature file or be directly inlined. -* f`placement`: The list of placement modifiers, in order. Each modifier has a f`type` field and depending on the placement modifier, extra fields for configuration. - -## Placement modifiers -Without any placement modifiers a feature is by default placed once at the most negative corner of the chunk at Y=0. Using a combination of different modifiers, this position can be altered. - -In general there are 3 categories of modifiers, although some modifiers fall in multiple categories: -* **Repeating**: changes how many times the feature should spawn - * [`count`](#count): Simple repeating count - * [`noise_based_count`](#noise_based_count): Variable count based on a noise map - * [`noise_threshold_count`](#noise_threshold_count): Two possible counts based on a noise map -* **Filter**: whether the feature should spawn based on conditions - * [`biome`](#biome): Checks the biome - * [`block_predicate_filter`](#block_predicate_filter): Checks a block predicate - * [`environment_scan`](#environment_scan): Scans up or down for blocks - * [`rarity_filter`](#rarity_filter): Simple probability - * [`surface_relative_threshold_filter`](#surface_relative_threshold_filter): Checks the height relative to the surface - * [`surface_water_depth_filter`](#surface_water_depth_filter): Checks the depth of the water -* **Transform**: changes the position of the feature in the chunk - * [`carving_mask`](#carving_mask): Returns all carved out blocks - * [`count_on_every_layer`](#count_on_every_layer): Count, in-square, and multi-layered heightmap in one - * [`environment_scan`](#environment_scan): Moves up or down based on block predicates - * [`height_range`](#height_range): Sets the Y coordinate using a height provider - * [`heightmap`](#heightmap): Sets the Y coordinate to the surface height - * [`in_square`](#in_square): Offsets the X and Z coordinates randomly in the chunk - * [`random_offset`](#random_offset): Applies a random offset - -## Modifier types - -### `biome` -Returns the current position if the biome at the current position includes this placed feature. Otherwise, returns nothing. - -> Note: can only be used in placed features that are directly referenced in a biome! - -*This placement modifier has no extra fields.* - -### `block_predicate_filter` -Checks for block(s) relative to the current position. If the predicate passes, the current position is returned. Otherwise, returns nothing. - -* f`predicate`: The predicate to check - * f`type`: The predicate type - * s`all_of`: Contains a list of predicates. All listed predicates must pass for the predicate to pass. - * s`any_of`: Contains list of predicates. At least one predicate must pass for the predicate to pass. - * s`has_sturdy_face`: Contains an offset and a direction. Checks if the block in the specified direction provides full support on that face. - * s`inside_world_bounds`: Contains an offset, with no extra fields. - * s`matching_block_tag`: Contains a block tag along with a block offset. If the block at the offset matches any block in the block tag, the predicate passes. - * s`matching_blocks`: Contains a list of blocks along with a block offset. If the block at the offset matches any block in the list, the predicate passes. - * s`matching_fluids`: Identical to `matching_blocks`, but takes a list of fluids instead. - * s`not`: Contains another predicate inside of it. If the predicate inside it fails, the `not` predicate passes. - * s`replaceable`: *Contains no extra fields* - * s`solid`: *Contains no extra fields* - * s`true`: Always passes. - * s`would_survive`: Contains an offset and a block state. If the block at the offset would survive, the predicate passes. - -### `carving_mask` -Returns all locations in the current chunk if they have been carved out by any configured carver. Importantly, this does not include noise caves. - -* f`step`: Either `air` or `liquid` - -### `count` -Returns copies of the current position. - -* f`count`: The number of placements at the current block position - -### `count_on_every_layer` -Returns block positions on every vertical layer, randomly spread within the chunk. - -* f`count`: The number of placements on each vertical layer - -### `environment_scan` -Searches either up or down for a target block condition within the step limit. If a suitable block is found, that position is returned. Otherwise, returns nothing. - -* f`direction_of_search`: Direction that the placement modifier searches, either `up` or `down` -* f`max_steps`: The max number of blocks that the placement modifier searches, must be an integer between `1` and `32` -* f`target_condition`: The [block predicate](#block_predicate_filter) a searched block must meet for that block position to be returned -* f`allowed_search_condition`: *(optional)* A [block predicate](#block_predicate_filter) blocks at each step must meet for the scan to continue - -### `height_range` -Modifies the vertical coordinate to be within the height range. - -* f`height`: The height provider the placements must be contained in - -### `heightmap` -Modifiers the vertical coordinate to match the provided heightmap. - -* f`heightmap`: The [heightmap type](/guides/heightmap-types/) that placements are placed on - -### `in_square` -Randomizes the placement horizontally in the chunk. It does this by adding a random value to both the X and Z coordinates between 0 and 15 (inclusive). - -*This placement modifier has no extra fields.* - -### `noise_based_count` -Returns copies of the current block position, based on a noise value at the current location. - -Uses a global 2D simplex noise with one octave. - -* f`noise_to_count_ratio`: Determines how strongly the noise affects the resulting count -* f`noise_factor`: Stretches the noise on the x-axis and z-axis, higher values lead to more spaced out noise peaks -* f`noise_offset`: *(optional)* Offsets the threshold where features are generated, defaults to 0 - -### `noise_threshold_count` -Returns copies of the current block position. The number of copies depends on whether or not the noise at the given position is above the `noise_level`. - -Uses a global 2D simplex noise with one octave. - -* f`noise_level`: The threshold value, useful range is `-1` to `1` -* f`below_noise`: The count if the noise value is below the f`noise_level` -* f`above_noise`: The count if the noise value is above the f`noise_level` - -### `random_offset` -Offsets the current block position on each axis. -*(While the x-axis and z-axis share a integer provider, they can be assigned different offsets.)* -* f`xz_spread`: The offset on the x-axis and z-axis, any integer between `-16` and `16` -* f`y_spread`: The offset on the y-axis, any integer between `-16` and `16` - -### `rarity_filter` -Either returns the current block position or nothing. The chance for the filter to pass is `1 / chance`. - -* f`chance`: An integer, must be at least 1 - -### `surface_relative_threshold_filter` -Checks if the heightmap is within a range, and returns the current position if so. If the check fails, nothing is returned, - -* f`heightmap`: The [heightmap type](/guides/heightmap-types) to use provider -* f`min_inclusive`: The minimum vertical coordinate that the heightmap must be in -* f`max_inclusive`: The maximum vertical coordinate that the heightmap must be in - -### `surface_water_depth_filter` -Returns the current position if the block's depth in water is not above the provided max water depth. Otherwise returns nothing. - -* f`max_water_depth`: The maximum depth in water the feature can be placed in. diff --git a/src/locales/en.json b/src/locales/en.json index e9ee53f6..fd1aab62 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -71,10 +71,6 @@ "generators.no_results": "No generators for this query", "github": "GitHub", "guides": "Guides", - "guides.all": "All guides", - "guides.search": "Search guides", - "guides.no_results.version": "No guides for this version", - "guides.no_results.query": "No guides for this query", "hide_output": "Hide output", "hide_preview": "Hide preview", "hide_project": "Hide project", diff --git a/src/locales/fr.json b/src/locales/fr.json index c7474e32..0983da16 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -50,10 +50,6 @@ "generators.search": "Chercher des générateurs", "github": "GitHub", "guides": "Tutoriels", - "guides.all": "Tous les guides", - "guides.no_results.query": "Pas de guides pour cette requête", - "guides.no_results.version": "Pas de guides pour cette version", - "guides.search": "Rechercher des guides", "hide_output": "Réduire le code généré", "hide_preview": "Cacher l'aperçu", "hide_project": "Réduire le projet", diff --git a/src/locales/ja.json b/src/locales/ja.json index 580fbfb9..0398288b 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -49,10 +49,6 @@ "generators.search": "生成機を検索", "github": "GitHub", "guides": "ガイド", - "guides.all": "すべてのガイド", - "guides.no_results.query": "このクエリに関するガイドはありません", - "guides.no_results.version": "このバージョンのガイドはありません", - "guides.search": "ガイドを検索する", "hide_output": "出力を非表示", "hide_preview": "プレビューを非表示", "hide_project": "プロジェクトを非表示にする", diff --git a/src/locales/ko.json b/src/locales/ko.json index 1889bb6b..b0a957e1 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -41,10 +41,6 @@ "generate_new_seed": "새로운 시드 만들기", "generate_new_uuid": "새로운 UUID 만들기", "github": "GitHub", - "guides.all": "모든 가이드", - "guides.no_results.query": "가이드 검색 결과가 없습니다", - "guides.no_results.version": "이 버전에는 가이드가 없습니다", - "guides.search": "가이드 찾기", "hide_output": "출력 숨기기", "hide_preview": "미리보기 숨기기", "hide_project": "프로젝트 숨기기", diff --git a/src/locales/ru.json b/src/locales/ru.json index 407a5204..72fb29de 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -55,10 +55,6 @@ "generators.no_results": "По этому запросу генераторы не найдены", "github": "GitHub", "guides": "Руководства", - "guides.all": "Все руководства", - "guides.search": "Поиск руководств", - "guides.no_results.version": "Нет руководств для этой версии", - "guides.no_results.query": "По этому запросу руководства не найдены", "hide_output": "Скрыть вывод", "hide_preview": "Скрыть визуализацию", "hide_project": "Скрыть проект", diff --git a/src/locales/zh-cn.json b/src/locales/zh-cn.json index 34d1080b..21da0c54 100644 --- a/src/locales/zh-cn.json +++ b/src/locales/zh-cn.json @@ -49,10 +49,6 @@ "generators.search": "搜索生成器", "github": "GitHub", "guides": "指南", - "guides.all": "全部指南", - "guides.no_results.query": "找不到相关的指南", - "guides.no_results.version": "该版本没有指南", - "guides.search": "搜索指南", "hide_output": "隐藏输出", "hide_preview": "隐藏预览", "hide_project": "隐藏项目", diff --git a/src/styles/global.css b/src/styles/global.css index 54ecc832..8d1f927c 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -2537,11 +2537,11 @@ hr { padding: 10px 0 15px; } -.whats-new-entry .guide-content { +.whats-new-entry .markdown-content { margin-top: 0; } -.whats-new-entry .guide-content img { +.whats-new-entry .markdown-content img { max-width: min(calc(100vw - 78px), 600px); background: linear-gradient(150deg, var(--background-6) 0%, var(--background-5) 100%); padding: 20px; @@ -2713,68 +2713,35 @@ hr { text-overflow: ellipsis; } -.guide { - padding-left: 32px; - padding-right: 32px; -} - -.guide > .badges-list { - margin-top: 12px; -} - -.guide-share.active { - fill: var(--accent-success); - color: var(--text-2); -} - -.guide .ad { - margin: 12px 0 8px; -} - -.guide .ad[data-ea-type="image"] { - float: right; - margin-left: 12px; -} - -.guide-toc { - display: inline-block; - border: 2px solid var(--background-6); - border-radius: 6px; - padding: 8px 16px; - line-height: 1.2; - font-size: 90%; - list-style-type: decimal; -} - -.guide-content { +.markdown-content { color: var(--text-2); margin-top: 12px; line-height: 1.5; word-wrap: break-word; } -.guide-content p { +.markdown-content p { margin-top: 0; margin-bottom: 10px; } -.guide-content h1, -.guide-content h2, -.guide-content h3, -.guide-content h4, -.guide-content h5, -.guide-content h6 { +.markdown-content h1, +.markdown-content h2, +.markdown-content h3, +.markdown-content h4, +.markdown-content h5, +.markdown-content h6 { margin: 1.2em 0 0.4em; position: relative; font-weight: normal; } -.guide-content h1 > [id], -.guide-content h2 > [id], -.guide-content h3 > [id], -.guide-content h4 > [id], -.guide-content h5 > [id], -.guide-content h6 > [id] { +.markdown-content h1 > [id], +.markdown-content h2 > [id], +.markdown-content h3 > [id], +.markdown-content h4 > [id], +.markdown-content h5 > [id], +.markdown-content h6 > [id] { fill: var(--text-3); opacity: 0; transition: opacity 0.2s; @@ -2784,77 +2751,77 @@ hr { cursor: pointer; } -.guide-content h1 > [id] *, -.guide-content h2 > [id] *, -.guide-content h3 > [id] *, -.guide-content h4 > [id] *, -.guide-content h5 > [id] *, -.guide-content h6 > [id] * { +.markdown-content h1 > [id] *, +.markdown-content h2 > [id] *, +.markdown-content h3 > [id] *, +.markdown-content h4 > [id] *, +.markdown-content h5 > [id] *, +.markdown-content h6 > [id] * { pointer-events: none; } -.guide-content h1:hover > [id], -.guide-content h2:hover > [id], -.guide-content h3:hover > [id], -.guide-content h4:hover > [id], -.guide-content h5:hover > [id], -.guide-content h6:hover > [id] { +.markdown-content h1:hover > [id], +.markdown-content h2:hover > [id], +.markdown-content h3:hover > [id], +.markdown-content h4:hover > [id], +.markdown-content h5:hover > [id], +.markdown-content h6:hover > [id] { opacity: 1; } -.guide-content h2 { +.markdown-content h2 { font-size: 24px; } -.guide-content blockquote { +.markdown-content blockquote { border-left: 4px solid var(--background-6); color: var(--text-3); padding-left: 0.7em; margin: 0.7em 0; } -.guide-content blockquote > p { +.markdown-content blockquote > p { padding: 0.3em 0; } -.guide-content a { +.markdown-content a { text-decoration: underline; color: var(--accent-primary); } -.guide-content ul, .guide-content ol { +.markdown-content ul, .markdown-content ol { padding-left: 1.6em; margin: 0.2em 0 0.5em; } -.guide-content li + li { +.markdown-content li + li { margin-top: 0.25em; } -.guide-content img { +.markdown-content img { border-radius: 0.2em; max-width: 100%; } -.guide-content table { +.markdown-content table { border-spacing: 0; } -.guide-content th { +.markdown-content th { border-bottom: 2px solid var(--background-6); padding: 4px 8px; } -.guide-content td { +.markdown-content td { border-bottom: 1px solid var(--background-6); padding: 4px 8px; } -.guide-content tbody tr:last-child td { +.markdown-content tbody tr:last-child td { border-bottom: none; } -.guide-content code { +.markdown-content code { display: inline-block; padding: 0.1em 0.4em; margin: 0; @@ -2865,16 +2832,16 @@ hr { font-size: 85%; } -.guide-content h1 code, -.guide-content h2 code, -.guide-content h3 code, -.guide-content h4 code, -.guide-content h5 code, -.guide-content h6 code { +.markdown-content h1 code, +.markdown-content h2 code, +.markdown-content h3 code, +.markdown-content h4 code, +.markdown-content h5 code, +.markdown-content h6 code { font-size: 100%; } -.guide-content pre > code { +.markdown-content pre > code { display: block; padding: 0.8em; margin-top: 4px; @@ -2882,19 +2849,19 @@ hr { overflow-x: auto; } -.guide-content .hljs-attr { +.markdown-content .hljs-attr { color: var(--editor-variable); } -.guide-content .hljs-string { +.markdown-content .hljs-string { color: var(--editor-string); } -.guide-content .hljs-number { +.markdown-content .hljs-number { color: var(--editor-number); } -.guide-content .hljs-keyword { +.markdown-content .hljs-keyword { color: var(--editor-constant); } diff --git a/vite.config.js b/vite.config.js index d5c98815..dd13a1e8 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,8 +1,5 @@ import preact from '@preact/preset-vite' import html from '@rollup/plugin-html' -import glob from 'fast-glob' -import fs from 'fs' -import yaml from 'js-yaml' import { env } from 'process' import { visualizer } from 'rollup-plugin-visualizer' import { defineConfig } from 'vite' @@ -10,22 +7,6 @@ import { viteStaticCopy } from 'vite-plugin-static-copy' const config = require('./src/config.json') const English = require('./src/locales/en.json') -const guides = glob.sync('src/guides/**/*.md').flatMap(g => { - const content = fs.readFileSync(g).toString('utf-8') - if (!content.startsWith('---')) return [] - try { - const frontMatter = yaml.load(content.substring(3, content.indexOf('---', 3))) - if (typeof frontMatter !== 'object') return [] - return [{ - id: g.replace('src/guides/', '').replace('.md', ''), - ...frontMatter, - }] - } catch (e) { - console.warn('Failed loading guide', g, e.message) - return [] - } -}) - export default defineConfig({ server: { port: 3000, @@ -57,13 +38,11 @@ export default defineConfig({ title: `${English[m.id] ?? ''} Generator${m.category === true ? 's' : ''} - ${getVersions(m)}`, template, })), - ...guides.map(g => { - return html({ - fileName: `guides/${g.id}/index.html`, - title: `${g.title} - Minecraft${g.versions ? ` ${g.versions.join(' ')}` : ''}`, - template, - }) - }), + ...config.legacyGuides.map(g => html({ + fileName: `guides/${g.id}/index.html`, + title: `${g.title} - ${getVersions()}`, + template, + })), ], }, }, @@ -72,7 +51,6 @@ export default defineConfig({ }, define: { __LATEST_VERSION__: env.latest_version, - __GUIDES__: guides, }, plugins: [ preact(), @@ -80,24 +58,9 @@ export default defineConfig({ targets: [ { src: 'src/styles/giscus.css', dest: 'assets' }, { src: 'src/styles/giscus-burn.css', dest: 'assets' }, - { src: 'src/guides/*', dest: 'guides' }, ], }), 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], - }) - } - }, - }, ], })