Add woodland canopies, sheltered dark oaks and exposed starter ores
Build Sanctuary / build (push) Canceled after 0s
Build Sanctuary / build (push) Canceled after 0s
This commit is contained in:
@@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.0-alpha.7 — 2026-09-08
|
||||
|
||||
- Forêts de chênes plus denses, y compris au cœur et sur les hauteurs de l’île,
|
||||
avec bouleaux, clairières fleuries et bois plus secs.
|
||||
- Vrais chênes noirs, champignons, podzol et mycélium sur les corniches intérieures
|
||||
humides ; mousse plus ponctuelle et rares poches de jungle/bambou.
|
||||
- Un emplacement facultatif pour un arbre remarquable (cerisier favorisé,
|
||||
épicéa, jungle, acacia, palétuvier ou chêne pâle), sans terrain ajouté.
|
||||
- Nappes de pierre, andésite, diorite et granite sur les affleurements ; dépôts
|
||||
épais de sable, gravier et argile associés aux bassins. Rares matières de
|
||||
soufre dans les profondeurs, sans grands bassins souterrains.
|
||||
- Petits filons de charbon, fer et cuivre autorisés à affleurer, avec des essais
|
||||
sur les roches de surface et les corniches pour les rendre repérables.
|
||||
- Nouvelle clé `sanctuary:sanctuary_woodland`, avec formes, hauteur, ciel et
|
||||
plans d’eau conservés. Créer un **nouveau monde Sanctuary** ; les sauvegardes
|
||||
alpha.6 et antérieures conservent leur génération.
|
||||
|
||||
Validation : dix tests serveur réussis sur chacune des graines `0`, `42` et
|
||||
`8675309`, arbres et minerais réellement observés, 1 800 ticks de fluides,
|
||||
et `check build assemblePack` réussi.
|
||||
|
||||
## 0.1.0-alpha.6 — 2026-09-08
|
||||
|
||||
- Palette tempérée plus douce, avec des couleurs communes pour l’herbe, le
|
||||
|
||||
@@ -22,11 +22,15 @@ décrits dans la vision ne sont pas encore implémentés.
|
||||
- Mod `sanctuary` indépendant et pack Sanctuary construit avec packwiz.
|
||||
- Preset **Sanctuary** sélectionnable à la création d'un monde, avec une île
|
||||
flottante finie, un terrain naturel et un extérieur vide.
|
||||
- Île tempérée aux teintes douces : prairies fleuries, bosquets, mousse et
|
||||
affleurements rocheux, avec des biomes qui varient aussi selon l’altitude. Les
|
||||
- Île tempérée aux teintes douces : forêts de chênes et de bouleaux, clairières
|
||||
fleuries et affleurements de pierre, andésite, diorite et granite. Les corniches
|
||||
intérieures accueillent chênes noirs et champignons ; les essences rares
|
||||
restent ponctuelles. Les
|
||||
formes de terrain reprennent le générateur 26.2, adapté à l'API 26.3.
|
||||
- Petits filons de charbon, fer, cuivre, or, redstone, lapis et diamant à des
|
||||
altitudes adaptées au terrain relevé. Les stocks se constatent après génération.
|
||||
altitudes adaptées au terrain relevé. Charbon, fer et cuivre peuvent aussi
|
||||
affleurer sur les roches de surface et les corniches. Les stocks se constatent
|
||||
après génération.
|
||||
- Spawn recherché sur le sol de l'île lors de la création. Les mondes ordinaires
|
||||
et les choix ultérieurs de spawn ne sont pas remplacés.
|
||||
- Nouveaux mondes sur 384 blocs (`Y=0..383`), île relevée de 64 blocs,
|
||||
@@ -48,9 +52,9 @@ le terrain : le spawn cherche un emplacement naturel. Le catalogue
|
||||
TerraMix, les continents déverrouillables, les océans, les ruines et
|
||||
les autres fonctionnalités restent à construire par tickets.
|
||||
|
||||
L’alpha.6 utilise de nouveaux paramètres de génération ; créer un **nouveau monde**
|
||||
pour découvrir ses biomes par altitude et ses eaux. Les sauvegardes alpha.2
|
||||
à alpha.5 conservent leur génération. Dappled Forest est désormais réservé aux
|
||||
L’alpha.7 utilise de nouveaux paramètres de génération ; créer un **nouveau monde**
|
||||
pour découvrir ses forêts, ses corniches humides et ses affleurements. Les sauvegardes alpha.2
|
||||
à alpha.6 conservent leur génération. Dappled Forest est désormais réservé aux
|
||||
futurs continents et reste présent dans les anciennes sauvegardes alpha.5. La validation de cet incrément est suivie dans [Validation](docs/testing.md).
|
||||
|
||||
Le premier champ de recherche climatique est défini : nord froid, sud chaud,
|
||||
@@ -75,7 +79,7 @@ sera une mise à jour explicite, avec vérification des API et des sauvegardes.
|
||||
| Fabric API | 0.160.0+26.3 |
|
||||
| Fabric Loom | 1.17.20 |
|
||||
| Gradle Wrapper | 9.5.1, distribution vérifiée par SHA-256 |
|
||||
| Sanctuary / pack | 0.1.0-alpha.6 |
|
||||
| Sanctuary / pack | 0.1.0-alpha.7 |
|
||||
|
||||
Java 25 et Python 3.11 ou plus récent sont nécessaires. Le script pack utilise
|
||||
uniquement la bibliothèque standard et repère aussi une installation Python
|
||||
@@ -102,7 +106,7 @@ décrits dans [Validation](docs/testing.md).
|
||||
|
||||
Résultats :
|
||||
|
||||
- `mods/sanctuary/build/libs/sanctuary-0.1.0-alpha.6.jar` : mod à installer avec
|
||||
- `mods/sanctuary/build/libs/sanctuary-0.1.0-alpha.7.jar` : mod à installer avec
|
||||
Fabric API sur la version Minecraft indiquée.
|
||||
- `build/packwiz/` : pack de développement complet, avec le mod construit et
|
||||
l'index vérifié. Voir [Installation packwiz](packwiz/README.md).
|
||||
|
||||
@@ -11,7 +11,9 @@ Les biomes de départ reprennent les configurations de forêt, plaine, forêt de
|
||||
bouleaux, forêt fleurie et Dappled Forest de Minecraft 26.3-pre-2, adaptées à
|
||||
une île finie. Les variantes alpha.6 réutilisent les végétations vanilla pour
|
||||
les prairies fleuries et les bosquets ; Dappled Forest reste disponible pour
|
||||
les sauvegardes alpha.5. Les règles des petits minerais sont adaptées à partir des
|
||||
les sauvegardes alpha.5. L’alpha.7 réemploie les arbres vanilla (dont chêne noir,
|
||||
cerisier et essences rares), les champignons, le bambou et les blocs de soufre
|
||||
de cette version, avec des conditions propres à l’île. Les règles des petits minerais sont adaptées à partir des
|
||||
features vanilla de cette même version. Les références de blocs, végétation et
|
||||
minerais sont résolues par Minecraft ; leurs textures et modèles ne sont pas inclus.
|
||||
|
||||
|
||||
@@ -173,6 +173,33 @@ dont Dappled Forest, aux futurs continents. L’île combine prairies fleuries,
|
||||
bosquets et zones rocheuses, avec des teintes cohérentes et une végétation
|
||||
effective sur les corniches inférieures. Cela ne livre pas encore les continents.
|
||||
|
||||
### WG-08 — Forêts de survie et minerais visibles — alpha.7
|
||||
|
||||
**Branche :** `codex/woodland-canopy`.
|
||||
|
||||
**But :** conserver les formes rocheuses appréciées en alpha.6 tout en donnant
|
||||
à l’île de vraies forêts de surface et des ressources de départ repérables.
|
||||
|
||||
**Critères d’acceptation :**
|
||||
|
||||
- Chênes majoritaires parmi les arbres de surface observés, bouleaux secondaires,
|
||||
avec des arbres au cœur de l’île et des clairières fleuries.
|
||||
- Chênes noirs réels et champignons sur des corniches intérieures naturelles ;
|
||||
jungle/bambou et matières de soufre rares et localisés.
|
||||
- Un éventuel arbre remarquable, choisi parmi les essences rares, sans ajout
|
||||
de terrain ni obligation de fournir chaque essence par graine.
|
||||
- Affleurements de pierre, andésite, diorite et granite ; sable et gravier
|
||||
associés aux eaux, avec des couches soutenues.
|
||||
- Charbon, fer et cuivre visibles au contact de l’air sur la roche, avec des
|
||||
petits filons sans quota corrigé après génération.
|
||||
- Démonstration dans le moteur, maintien des eaux après 1 800 ticks et
|
||||
conservation des anciennes générations. Publication packwiz et mise à jour
|
||||
de l’instance Prism existante en conservant ses données personnelles.
|
||||
|
||||
**Vérification alpha.7 :** les trois graines de référence passent les tests
|
||||
du moteur, dont les forêts, les minerais exposés et les eaux après 1 800 ticks.
|
||||
Les observations et leurs limites sont consignées dans [Validation](testing.md).
|
||||
|
||||
## Réserve de thèmes futurs
|
||||
|
||||
Ces thèmes servent à retrouver la vision, pas à demander leur implémentation immédiate. On en extrait un ticket seulement lorsqu'il devient utile au prochain incrément jouable.
|
||||
|
||||
@@ -37,6 +37,14 @@ La répartition tient compte de l’altitude, y compris dans les strates inféri
|
||||
La variation locale et l’humidité dépendent de la graine ; elles ne
|
||||
constituent pas encore le champ de recherche directionnel des continents.
|
||||
|
||||
L’alpha.7 densifie les forêts de chênes et de bouleaux en surface et donne
|
||||
aux corniches intérieures humides des chênes noirs et des champignons.
|
||||
Des champignons vanilla peuvent aussi se rencontrer en surface. Les
|
||||
clairières fleuries et les affleurements restent présents. Les essences rares
|
||||
et un éventuel arbre remarquable dépendent du terrain ; chaque graine n’est
|
||||
pas tenue de fournir tous les bois. Les minerais de départ peuvent affleurer,
|
||||
avec des petits filons et sans correction des stocks après comptage.
|
||||
|
||||
## Eau de surface et exploration
|
||||
|
||||
L'île de départ doit pouvoir accueillir naturellement des étangs et lacs de
|
||||
|
||||
+6
-2
@@ -19,7 +19,7 @@ Après les vérifications, le commit et le push de la branche du ticket, le scri
|
||||
de publication réalise les étapes de release et de canal ci-dessous :
|
||||
|
||||
```sh
|
||||
python3 scripts/publish_pack.py --notes-file chemin/vers/notes.md --asset build/Sanctuary-0.1.0-alpha.6.mrpack
|
||||
python3 scripts/publish_pack.py --notes-file chemin/vers/notes.md --asset build/Sanctuary-0.1.0-alpha.7.mrpack
|
||||
```
|
||||
|
||||
Les options sont facultatives. Ce script **publie** sur le Git configuré dans
|
||||
@@ -38,7 +38,7 @@ La procédure complète, également utilisable manuellement :
|
||||
3. Préparer les métadonnées de la livraison, avec l'URL exacte du futur JAR :
|
||||
|
||||
```sh
|
||||
python3 scripts/pack.py release https://git.botsu.net/koka/sanctuary-beta/releases/download/v0.1.0-alpha.6/sanctuary-0.1.0-alpha.6.jar
|
||||
python3 scripts/pack.py release https://git.botsu.net/koka/sanctuary-beta/releases/download/v0.1.0-alpha.7/sanctuary-0.1.0-alpha.7.jar
|
||||
```
|
||||
|
||||
4. Pousser le commit source vérifié. Créer une release Gitea correspondant à ce
|
||||
@@ -127,6 +127,10 @@ L’alpha.6 utilise à son tour `sanctuary:sanctuary_layered` pour ses biomes pa
|
||||
altitude et sa nouvelle hydrologie. Créer un nouveau monde Sanctuary ; les
|
||||
sauvegardes alpha.5 conservent notamment leur palette avec Dappled Forest.
|
||||
|
||||
L’alpha.7 sélectionne `sanctuary:sanctuary_woodland` pour ses forêts, ses
|
||||
roches variées et ses minerais affleurants. Les mondes alpha.6 gardent
|
||||
`sanctuary:sanctuary_layered` ; aucune régénération de chunks n’est effectuée.
|
||||
|
||||
Références officielles : [installation packwiz](https://packwiz.infra.link/tutorials/installing/packwiz-installer/),
|
||||
[commandes Prism](https://prismlauncher.org/wiki/help-pages/custom-commands/),
|
||||
[bootstrap v0.0.3](https://github.com/packwiz/packwiz-installer-bootstrap/releases/tag/v0.0.3).
|
||||
|
||||
+64
-4
@@ -81,17 +81,17 @@ Les neuf tests Sanctuary vérifient :
|
||||
tandis que les anciens paramètres restent à 256 blocs. Les nuages sont
|
||||
au-dessus de l'île, à Y=352,33.
|
||||
6. Aucun plancher solide n’apparaît sous l’île, à Y=0..15. Dans les générations
|
||||
alpha.5 et alpha.6, seules les eaux des cascades déclarées peuvent traverser cette marge.
|
||||
alpha.5 à alpha.7, seules les eaux des cascades déclarées peuvent traverser cette marge.
|
||||
7. Le relevé après génération compte exactement tous les états des blocs des
|
||||
chunks demandés, avec des totaux cohérents et une complétude explicite.
|
||||
Voir [Expansion et ressources](expansion.md) pour le mode complet facultatif.
|
||||
8. Le plan hydrologique se retrouve dans les vrais chunks après décoration :
|
||||
profils épais de sédiments, bassins retenus, raccords entre chunks, canne à
|
||||
sucre valide, niches rocheuses et descente réelle des cascades. Les cinq
|
||||
biomes et les minerais sont inspectés sur le terrain. Une réserve de lave
|
||||
sucre valide, niches rocheuses et descente réelle des cascades. La palette
|
||||
active et les minerais sont inspectés sur le terrain. Une réserve de lave
|
||||
présente conserve ses 18 sources, ses supports et son accès après simulation.
|
||||
9. Les anciennes clés gardent leur traitement d’origine. Seuls les nouveaux
|
||||
paramètres activent les biomes par altitude et les eaux de l’alpha.6.
|
||||
paramètres activent les forêts et les eaux de l’alpha.7.
|
||||
|
||||
La recherche de spawn parcourt l'île finie, par anneaux de quatre blocs jusqu'à
|
||||
288 blocs du centre. Elle examine d'abord la hauteur brute pour éviter de
|
||||
@@ -188,6 +188,66 @@ Pour cet essai visuel en monde de développement créatif, comparer la même vue
|
||||
Y=63 ni assombrissement d'altitude au passage de Y=32. Les brouillards de l'eau,
|
||||
de la météo et des effets d'aveuglement ou d'obscurité doivent rester présents.
|
||||
|
||||
## Contrôles et validation alpha.7 — 8 septembre 2026
|
||||
|
||||
`WoodlandDiagnostics` reprend les preuves hydrologiques et ajoute les forêts,
|
||||
les champignons sous plafond, les roches exposées et les minerais visibles.
|
||||
Les arbres sont comptés par pieds de troncs sur le sol naturel, avec au moins
|
||||
trois bûches verticales et des feuilles réellement observées. Le chêne noir
|
||||
requiert un pied principal de 2×2 et trois couches de support par pied ; ses
|
||||
branches retombantes ne comptent pas comme de nouveaux arbres. Podzol et
|
||||
mycélium sont des sols explicites : le tag `minecraft:dirt` de cette version
|
||||
ne les contient pas.
|
||||
|
||||
Les essais utilisent des mondes neufs, le vrai preset de production et
|
||||
Minecraft 26.3-pre-2 / Java 25 / Fabric Loader 0.19.5. Les dix tests requis
|
||||
passent sur chacune des trois graines. `check build assemblePack` passe en
|
||||
3 min 41 s sur la graine 0, avec les huit tests purs de forme, hydrologie,
|
||||
lave, écologie et nouveaux bois. Les exports de densité et le relevé général
|
||||
facultatifs sont désactivés ; les contrôles de densité restent actifs.
|
||||
|
||||
| Graine | Chunks FULL inspectés | Chênes de surface | Bouleaux de surface | Chênes à rayon ≤128 | Chênes noirs inférieurs | Minerais exposés dehors : charbon / fer / cuivre |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | --- |
|
||||
| `0` | 167 | 292 | 263 | 218 | 30 | 4 / 19 / 5 |
|
||||
| `42` | 154 | 313 | 125 | 250 | 13 | 8 / 3 / 13 |
|
||||
| `8675309` | 167 | 336 | 99 | 272 | 36 | 7 / 6 / 9 |
|
||||
|
||||
Ces nombres décrivent un échantillon borné : les eaux et leur voisinage, des
|
||||
cibles écologiques et l’emplacement de l’arbre remarquable. Ce n’est pas un
|
||||
inventaire complet de l’île ni un pourcentage représentatif de toutes ses
|
||||
surfaces. Les sols sont mesurés sous les canopées. Les minerais recensés dans
|
||||
la dernière colonne ont une face d’air réelle, ouverte vers le ciel ou vers
|
||||
une paroi dégagée sur douze blocs ; les faces dans de petites cavités sont
|
||||
comptées séparément. Les trois roches présentent des nappes contiguës exposées.
|
||||
|
||||
La graine 42 démontre un cerisier remarquable en `(-88, 251, -88)`, avec son
|
||||
tronc, ses feuilles et 21 bûches dans le volume prévu. Le site sélectionné sur
|
||||
la graine 0 ne produit pas d’arbre rare : l’espace et les conditions après
|
||||
décoration restent déterminants. Aucun terrain n’est ajouté pour le forcer.
|
||||
Les autres essences rares et le soufre ne sont pas garantis sur chaque graine.
|
||||
|
||||
Les eaux sont vérifiées après décoration puis pendant 1 800 ticks réels dans
|
||||
des chunks actifs, avec témoins indépendants du fonctionnement des fluides.
|
||||
Les bassins et les dix-huit sources de chaque niche de lave sont conservés ;
|
||||
les cascades restent reliées à leurs sources et dans l’emprise observée.
|
||||
Les pieds des arbres et les champignons observés gardent leur support. Les
|
||||
sédiments sont comparés à leur matériau prévu sur toutes leurs couches ; une
|
||||
roche peut être remplacée seulement par les roches, minerais ou dépôts de
|
||||
terre effectivement configurés. Les berges de sable et gravier sont comptées
|
||||
sur les vrais blocs, y compris par profondeur.
|
||||
|
||||
Les anciens générateurs restent isolés : les 77 fichiers historiques suivis
|
||||
gardent leur SHA-256. La réentrée au post-traitement après consommation des
|
||||
marqueurs respecte une modification ultérieure de bouche de source sur les
|
||||
trois graines. Aucun monde de joueur n’est ouvert par ces tests.
|
||||
|
||||
Preuves locales ignorées par Git : `build/alpha7-build.log`,
|
||||
`build/alpha7-seed42.log`, `build/alpha7-seed8675309.log`, et les fichiers
|
||||
`woodland-seed-<seed>-<phase>.json`, `-canopy.png`, `-lower-terraces.png` et
|
||||
profils de sources dans `mods/sanctuary/build/run/gameTest/diagnostics/`.
|
||||
Les cartes montrent des lectures de blocs ; l’appréciation du paysage dans
|
||||
le client reste à faire lors du prochain essai.
|
||||
|
||||
## Contrôles alpha.6
|
||||
|
||||
`layeredHydrologySmoke` vérifie les bassins sans ruisseau de secours, les
|
||||
|
||||
+14
-10
@@ -66,16 +66,20 @@ remplis d'eau ne sont pas retenus pour cette île. Le terrain doit laisser voir
|
||||
dessous sculpté et dégagé, dans un monde de **384 blocs de hauteur**, avec des
|
||||
nuages relevés et sans disque noir artificiel apparaissant sous un seuil d'altitude.
|
||||
|
||||
L’ambiance de départ doit rester douce et tempérée, avec des bosquets,
|
||||
des prairies fleuries et de larges zones rocheuses. Les biomes très contrastés
|
||||
de Minecraft 26.3, dont Dappled Forest, sont réservés aux futurs continents.
|
||||
Les biomes et la végétation varient aussi en hauteur : les corniches inférieures
|
||||
peuvent porter des bosquets, de la mousse et des fleurs lorsque leur surface
|
||||
s’y prête. Quelques sources de paroi et ruissellements relient ces étages.
|
||||
Les plages s’inspirent des nappes de
|
||||
sable des générations Alpha/Beta : elles peuvent relier des poches d’eau, tandis
|
||||
que d’autres rives restent rocheuses ou enherbées. Les quelques cascades servent
|
||||
également d’ascenseurs d’eau pour circuler verticalement.
|
||||
L’ambiance de départ doit rester douce et tempérée, avec de véritables forêts
|
||||
et des clairières fleuries, quelques zones plus sèches et de larges masses
|
||||
rocheuses mêlant pierre, andésite, diorite et granite. Les nappes de sable et
|
||||
de gravier accompagnent les eaux. Charbon, fer et cuivre doivent aussi pouvoir
|
||||
affleurer sur la roche exposée pour commencer la survie.
|
||||
|
||||
Les bois dominants sont le chêne, le chêne noir et le bouleau : chênes et
|
||||
bouleaux en surface, chênes noirs et champignons dans l’intérieur plus humide,
|
||||
avec moins de mousse uniforme. Épicéa, jungle, acacia, palétuvier et chêne pâle
|
||||
restent rares mais possibles ; du bambou et de rares poches de soufre peuvent
|
||||
se rencontrer dans les profondeurs. Un arbre remarquable isolé peut être un
|
||||
cerisier rose ou une autre de ces essences rares, lorsque le terrain convient.
|
||||
Les biomes très contrastés de Minecraft 26.3, dont Dappled Forest, restent
|
||||
réservés aux futurs continents.
|
||||
|
||||
L’île doit offrir les ressources nécessaires aux premières étapes de Minecraft,
|
||||
en quantités modestes pour pousser à explorer les expansions lors des grands
|
||||
|
||||
+67
-3
@@ -47,8 +47,9 @@ de test et les sauvegardes personnelles doivent rester distincts.
|
||||
Il n'y a ni plancher de bedrock,
|
||||
ni mer globale, ni reprise du terrain à distance. Le Nether et l'End restent
|
||||
ceux de Minecraft.
|
||||
- Les nouveaux mondes utilisent une palette tempérée de prairies, de bosquets,
|
||||
de corniches moussues et de zones rocheuses, répartie aussi en hauteur.
|
||||
- Les nouveaux mondes utilisent une palette tempérée de forêts de chênes et de
|
||||
bouleaux, de clairières fleuries et de zones rocheuses. Les strates intérieures
|
||||
portent des chênes noirs et des champignons sur leurs corniches naturelles.
|
||||
Dappled Forest est réservé aux futurs continents. Leur végétation et leurs animaux proviennent
|
||||
de Minecraft 26.3-pre-2. Les nouveaux identifiants ne reprennent pas les tags
|
||||
de structures vanilla, afin de ne pas placer leurs structures dans le vide.
|
||||
@@ -57,7 +58,7 @@ de test et les sauvegardes personnelles doivent rester distincts.
|
||||
rocheuses. Les arbres et les petits filons ont besoin du terrain existant.
|
||||
Aucun mod de biomes externe n’est nécessaire.
|
||||
|
||||
L’alpha.6 associe ces biomes aux plages, aux eaux et aux petits filons décrits
|
||||
L’alpha.7 associe ces biomes aux plages, aux eaux et aux petits filons décrits
|
||||
ci-dessous. Les ressources de survie ne se limitent pas au bois et à la pierre,
|
||||
mais cet incrément ne garantit pas encore une partie Minecraft complète sur
|
||||
chaque seed. L’accès à chaque progression vanilla et les ressources renouvelables
|
||||
@@ -450,3 +451,66 @@ chunks sauvegardés.
|
||||
La version de génération et les emprises doivent être gelées avant les premières
|
||||
sauvegardes destinées à durer. Ce prototype ne promet pas encore de migration
|
||||
automatique des mondes entre deux versions de terrain.
|
||||
|
||||
|
||||
## Forêts, corniches humides et affleurements — génération v7
|
||||
|
||||
L’alpha.7 crée les nouveaux mondes avec `sanctuary:sanctuary_woodland` et
|
||||
`sanctuary:woodland_island`. La densité `sanctuary:final_density_384`, les
|
||||
formes rocheuses, la hauteur et le ciel restent identiques. Les plans des
|
||||
bassins, sources et petites niches de lave reprennent les algorithmes alpha.6.
|
||||
Les anciens paramètres, biomes et features sont conservés ; cette livraison
|
||||
ne modifie pas les mondes existants.
|
||||
|
||||
La palette comporte huit biomes :
|
||||
|
||||
| Identifiant | Rôle |
|
||||
| --- | --- |
|
||||
| `sanctuary:woodland_oak_forest` | Forêt de chênes dominante, bouleaux secondaires |
|
||||
| `sanctuary:woodland_birch_forest` | Forêt de bouleaux complémentaire |
|
||||
| `sanctuary:woodland_clearing` | Clairière fleurie |
|
||||
| `sanctuary:woodland_dry_woodland` | Bois sec plus clairsemé |
|
||||
| `sanctuary:woodland_rocky_heath` | Masses rocheuses exposées |
|
||||
| `sanctuary:woodland_dark_grove` | Corniches humides à chênes noirs et champignons |
|
||||
| `sanctuary:woodland_bamboo_grove` | Rare intérieur à jungle et bambou |
|
||||
| `sanctuary:woodland_sulfur_depths` | Rare poche profonde de soufre sur roche existante |
|
||||
|
||||
Une altitude élevée ne transforme plus automatiquement une forêt en prairie
|
||||
ou en roche. Les forêts utilisent les véritables arbres vanilla avec leurs
|
||||
conditions de croissance ; les affleurements sont des patches horizontaux
|
||||
et des variations de matériau sur le terrain existant.
|
||||
|
||||
`woodland_groves` place de vrais chênes noirs sur des sols naturels de 2×2,
|
||||
avec trois blocs de support et une place suffisante pour le tronc et la
|
||||
canopée sous le plafond. Des champignons accompagnent les sols de podzol et
|
||||
de mycélium, avec quelques touches de mousse. La jungle et le bambou restent
|
||||
limités aux rares poches qui leur conviennent.
|
||||
|
||||
Un seul emplacement remarquable est recherché par graine, avec une essence
|
||||
choisie parmi cerisier (favorisé), épicéa, jungle, acacia, palétuvier et chêne
|
||||
pâle. Il ne produit pas de terrain : si le site ou les conditions de l’arbre
|
||||
vanilla ne conviennent pas, il ne pousse pas. Ce n’est pas une garantie de
|
||||
chaque essence sur chaque île. Aucun cœur de Creaking n’est ajouté par l’arbre
|
||||
pâle utilisé ici.
|
||||
|
||||
Les affleurements mêlent des nappes cohérentes de pierre, andésite, diorite et
|
||||
granite. Les berges conservent leur excavation limitée et leurs dépôts de
|
||||
3 à 5 blocs, avec des patches de sable, gravier, argile et roche. Les plantations de `woodland_groves` évitent les sources, leurs exutoires
|
||||
et les niches de lave. Les décorations vanilla conservent leurs placements ;
|
||||
le traitement unique après génération peut rouvrir la seule bouche de source
|
||||
déclarée si une plante l’obstrue. Le soufre
|
||||
reste une matière rare des profondeurs ; les grands bassins et sources
|
||||
vanilla du biome Sulfur Caves ne sont pas activés.
|
||||
|
||||
Les anciens petits filons souterrains de charbon, fer et cuivre étaient peu
|
||||
susceptibles d’atteindre les surfaces hautes ; leur réglage écartait aussi une
|
||||
partie des blocs voisins de l’air. Les nouvelles features `woodland_ore_*`
|
||||
utilisent des tailles vanilla limitées (`size=6` pour le charbon, `size=5`
|
||||
pour fer/cuivre), sans garantir ce nombre de blocs produits par filon,
|
||||
autorisent cette exposition et ajoutent des essais aléatoires sur les roches
|
||||
de surface et les corniches rencontrées depuis l’air. Elles remplacent
|
||||
seulement les roches naturelles reconnues par Minecraft, dont andésite,
|
||||
diorite et granite. Les autres minerais et les anciens générateurs gardent
|
||||
leurs réglages ; aucune quantité cible n’est réinjectée après mesure.
|
||||
|
||||
La version et les graines de validation sont consignées dans [Validation](testing.md).
|
||||
|
||||
+2
-2
@@ -8,6 +8,6 @@ loader_version=0.19.5
|
||||
loom_version=1.17.20
|
||||
fabric_api_version=0.160.0+26.3
|
||||
|
||||
mod_version=0.1.0-alpha.6
|
||||
pack_version=0.1.0-alpha.6
|
||||
mod_version=0.1.0-alpha.7
|
||||
pack_version=0.1.0-alpha.7
|
||||
maven_group=fr.koka.sanctuary
|
||||
|
||||
@@ -130,3 +130,20 @@ tasks.register('layeredEcologySmoke', JavaExec) {
|
||||
}
|
||||
|
||||
tasks.named('check') { dependsOn('layeredEcologySmoke') }
|
||||
|
||||
// Alpha.7 keeps previous biome palettes and generators unchanged.
|
||||
tasks.register('woodlandPaletteSmoke', JavaExec) {
|
||||
group = 'verification'
|
||||
description = 'Check surface forest coverage and bounded rare interior biomes.'
|
||||
dependsOn('testClasses')
|
||||
classpath = sourceSets.test.runtimeClasspath
|
||||
mainClass = 'fr.koka.sanctuary.worldgen.WoodlandPaletteSmoke'
|
||||
}
|
||||
tasks.register('woodlandGroveSmoke', JavaExec) {
|
||||
group = 'verification'
|
||||
description = 'Check natural tree supports and canopy space without creating terrain.'
|
||||
dependsOn('testClasses')
|
||||
classpath = sourceSets.test.runtimeClasspath
|
||||
mainClass = 'fr.koka.sanctuary.worldgen.WoodlandGroveSmoke'
|
||||
}
|
||||
tasks.named('check') { dependsOn('woodlandPaletteSmoke', 'woodlandGroveSmoke') }
|
||||
|
||||
+10
-4
@@ -3,6 +3,7 @@ package fr.koka.sanctuary.gametest;
|
||||
import fr.koka.sanctuary.worldgen.SanctuarySpawn;
|
||||
import fr.koka.sanctuary.worldgen.NaturalHydrologyRuntime;
|
||||
import fr.koka.sanctuary.worldgen.LayeredHydrologyRuntime;
|
||||
import fr.koka.sanctuary.worldgen.WoodlandHydrologyRuntime;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import fr.koka.sanctuary.worldgen.IslandShape;
|
||||
@@ -30,7 +31,8 @@ public final class SanctuaryWorldGameTests {
|
||||
@GameTest(maxTicks = 3000)
|
||||
public void generatedSurfaceWaterRemainsContained(GameTestHelper helper) throws java.io.IOException {
|
||||
var generator = (NoiseBasedChunkGenerator) helper.getLevel().getChunkSource().getGenerator();
|
||||
if (LayeredHydrologyRuntime.enabled(generator)) LayeredHydrologyDiagnostics.start(helper);
|
||||
if (WoodlandHydrologyRuntime.enabled(generator)) WoodlandDiagnostics.start(helper);
|
||||
else if (LayeredHydrologyRuntime.enabled(generator)) LayeredHydrologyDiagnostics.start(helper);
|
||||
else if (NaturalHydrologyRuntime.enabled(generator)) NaturalHydrologyDiagnostics.start(helper);
|
||||
else HydrologyDiagnostics.start(helper);
|
||||
}
|
||||
@@ -38,7 +40,8 @@ public final class SanctuaryWorldGameTests {
|
||||
@GameTest(maxTicks = 200)
|
||||
public void hydrologyDoesNotActivateForSavedLegacySettings(GameTestHelper helper) {
|
||||
var generator = (NoiseBasedChunkGenerator) helper.getLevel().getChunkSource().getGenerator();
|
||||
if (LayeredHydrologyRuntime.enabled(generator)) LayeredHydrologyDiagnostics.verifyLegacyIsolation(helper);
|
||||
if (WoodlandHydrologyRuntime.enabled(generator)) WoodlandDiagnostics.verifyLegacyIsolation(helper);
|
||||
else if (LayeredHydrologyRuntime.enabled(generator)) LayeredHydrologyDiagnostics.verifyLegacyIsolation(helper);
|
||||
else if (NaturalHydrologyRuntime.enabled(generator)) NaturalHydrologyDiagnostics.verifyLegacyIsolation(helper);
|
||||
else HydrologyDiagnostics.verifyLegacyIsolation(helper);
|
||||
helper.succeed();
|
||||
@@ -117,7 +120,8 @@ public final class SanctuaryWorldGameTests {
|
||||
helper.assertTrue(chunk != null, "The lower-margin test needs a fully generated chunk");
|
||||
if (chunk.getSection(0).hasOnlyAir()) continue;
|
||||
var generator = (NoiseBasedChunkGenerator) helper.getLevel().getChunkSource().getGenerator();
|
||||
helper.assertTrue(NaturalHydrologyRuntime.enabled(generator) || LayeredHydrologyRuntime.enabled(generator),
|
||||
helper.assertTrue(NaturalHydrologyRuntime.enabled(generator) || LayeredHydrologyRuntime.enabled(generator)
|
||||
|| WoodlandHydrologyRuntime.enabled(generator),
|
||||
"The legacy island must leave its lower margin entirely empty");
|
||||
for (int x = chunk.getPos().getMinBlockX(); x <= chunk.getPos().getMaxBlockX(); x++) {
|
||||
for (int z = chunk.getPos().getMinBlockZ(); z <= chunk.getPos().getMaxBlockZ(); z++) {
|
||||
@@ -125,7 +129,9 @@ public final class SanctuaryWorldGameTests {
|
||||
BlockPos p = new BlockPos(x, y, z);
|
||||
var state = chunk.getBlockState(p);
|
||||
helper.assertTrue(state.isAir() || state.getFluidState().is(FluidTags.WATER)
|
||||
&& (LayeredHydrologyRuntime.enabled(generator)
|
||||
&& (WoodlandHydrologyRuntime.enabled(generator)
|
||||
? WoodlandDiagnostics.isWithinSpringInspectionFootprint(WoodlandHydrologyRuntime.woodlandPlan(helper.getLevel()), x, z)
|
||||
: LayeredHydrologyRuntime.enabled(generator)
|
||||
? LayeredHydrologyDiagnostics.isWithinSpringInspectionFootprint(LayeredHydrologyRuntime.layeredPlan(helper.getLevel()), x, z)
|
||||
: NaturalHydrologyDiagnostics.isWithinSpringInspectionFootprint(NaturalHydrologyRuntime.naturalPlan(helper.getLevel()), x, z)),
|
||||
"The lower margin has no artificial floor; water must lie in the finite spring inspection footprint, with provenance checked by the full fluid diagnostic: " + p);
|
||||
|
||||
+1773
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,9 @@
|
||||
package fr.koka.sanctuary;
|
||||
|
||||
import fr.koka.sanctuary.worldgen.MainIslandDensity;
|
||||
import fr.koka.sanctuary.worldgen.WoodlandIslandBiomeSource;
|
||||
import fr.koka.sanctuary.worldgen.WoodlandShoreSugarCaneFeature;
|
||||
import fr.koka.sanctuary.worldgen.WoodlandGrovesFeature;
|
||||
import fr.koka.sanctuary.worldgen.NaturalShoreSugarCaneFeature;
|
||||
import fr.koka.sanctuary.worldgen.TemperateIslandBiomeSource;
|
||||
import fr.koka.sanctuary.worldgen.LayeredIslandBiomeSource;
|
||||
@@ -31,6 +34,9 @@ public final class SanctuaryMod implements ModInitializer {
|
||||
Registry.register(BuiltInRegistries.FEATURE_TYPE, id("layered_shore_sugar_cane"), LayeredShoreSugarCaneFeature.CODEC);
|
||||
Registry.register(BuiltInRegistries.FEATURE_TYPE, id("lower_terrace_vegetation"), LowerTerraceVegetationFeature.CODEC);
|
||||
Registry.register(BuiltInRegistries.BIOME_SOURCE, id("layered_island"), LayeredIslandBiomeSource.CODEC);
|
||||
Registry.register(BuiltInRegistries.BIOME_SOURCE, id("woodland_island"), WoodlandIslandBiomeSource.CODEC);
|
||||
Registry.register(BuiltInRegistries.FEATURE_TYPE, id("woodland_shore_sugar_cane"), WoodlandShoreSugarCaneFeature.CODEC);
|
||||
Registry.register(BuiltInRegistries.FEATURE_TYPE, id("woodland_groves"), WoodlandGrovesFeature.CODEC);
|
||||
LOGGER.info("Sanctuary initialized: the Sanctuary world preset is available.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package fr.koka.sanctuary.mixin;
|
||||
import fr.koka.sanctuary.worldgen.HydrologyRuntime;
|
||||
import fr.koka.sanctuary.worldgen.NaturalHydrologyRuntime;
|
||||
import fr.koka.sanctuary.worldgen.LayeredHydrologyRuntime;
|
||||
import fr.koka.sanctuary.worldgen.WoodlandHydrologyRuntime;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.minecraft.core.Holder;
|
||||
@@ -27,7 +28,12 @@ public abstract class SurfaceHydrologyMixin {
|
||||
StructureManager structures, BiomeManager biomeManager, WorldGenRegion region,
|
||||
Set<Holder<Biome>> biomes, CallbackInfoReturnable<CompletableFuture<ChunkAccess>> callback) {
|
||||
var generator = (NoiseBasedChunkGenerator) (Object) this;
|
||||
if (LayeredHydrologyRuntime.enabled(generator)) {
|
||||
if (WoodlandHydrologyRuntime.enabled(generator)) {
|
||||
callback.setReturnValue(callback.getReturnValue().thenApply(generated -> {
|
||||
WoodlandHydrologyRuntime.apply(generator, randomState, generated);
|
||||
return generated;
|
||||
}));
|
||||
} else if (LayeredHydrologyRuntime.enabled(generator)) {
|
||||
callback.setReturnValue(callback.getReturnValue().thenApply(generated -> {
|
||||
LayeredHydrologyRuntime.apply(generator, randomState, generated);
|
||||
return generated;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package fr.koka.sanctuary.mixin;
|
||||
|
||||
import fr.koka.sanctuary.worldgen.WoodlandSpringOutlets;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/** Finish only pending generation markers; completed saved chunks are never repaired on reload. */
|
||||
@Mixin(LevelChunk.class)
|
||||
public abstract class WoodlandSpringOutletMixin {
|
||||
@Unique
|
||||
private WoodlandSpringOutlets.Pending sanctuary$pendingWoodlandOutlets = WoodlandSpringOutlets.Pending.EMPTY;
|
||||
|
||||
@Inject(method = "postProcessGeneration", at = @At("HEAD"))
|
||||
private void sanctuary$captureWoodlandOutlets(ServerLevel level, CallbackInfo callback) {
|
||||
sanctuary$pendingWoodlandOutlets = WoodlandSpringOutlets.capturePending(level, (LevelChunk) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "postProcessGeneration", at = @At("TAIL"))
|
||||
private void sanctuary$finishWoodlandOutlets(ServerLevel level, CallbackInfo callback) {
|
||||
var pending = sanctuary$pendingWoodlandOutlets;
|
||||
sanctuary$pendingWoodlandOutlets = WoodlandSpringOutlets.Pending.EMPTY;
|
||||
WoodlandSpringOutlets.finish(level, (LevelChunk) (Object) this, pending);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ public final class SanctuarySpawn {
|
||||
|
||||
public static final ResourceKey<NoiseGeneratorSettings> LAYERED_SETTINGS =
|
||||
ResourceKey.create(Registries.NOISE_SETTINGS, SanctuaryMod.id("sanctuary_layered"));
|
||||
public static final ResourceKey<NoiseGeneratorSettings> WOODLAND_SETTINGS =
|
||||
ResourceKey.create(Registries.NOISE_SETTINGS, SanctuaryMod.id("sanctuary_woodland"));
|
||||
|
||||
private SanctuarySpawn() {}
|
||||
|
||||
@@ -36,7 +38,8 @@ public final class SanctuarySpawn {
|
||||
&& (generator.generatorSettings().is(SETTINGS) || generator.generatorSettings().is(RAISED_SETTINGS)
|
||||
|| generator.generatorSettings().is(HYDROLOGY_SETTINGS)
|
||||
|| generator.generatorSettings().is(NATURAL_SETTINGS)
|
||||
|| generator.generatorSettings().is(LAYERED_SETTINGS));
|
||||
|| generator.generatorSettings().is(LAYERED_SETTINGS)
|
||||
|| generator.generatorSettings().is(WOODLAND_SETTINGS));
|
||||
}
|
||||
|
||||
/** Called only during first creation; saved spawns and /setworldspawn survive subsequent loads. */
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
/** Alpha.7 keeps forest at every surface altitude; depth changes the sheltered interior palette. */
|
||||
public final class WoodlandBiomePalette {
|
||||
public enum Kind {
|
||||
OAK_FOREST, BIRCH_FOREST, CLEARING, DRY_WOODLAND, ROCKY_HEATH,
|
||||
DARK_GROVE, BAMBOO_GROVE, SULFUR_DEPTHS
|
||||
}
|
||||
|
||||
private WoodlandBiomePalette() {}
|
||||
|
||||
public static Kind select(int blockY, float variation, float moisture) {
|
||||
double elevation = blockY - Math.clamp(variation, -1.0F, 1.0F) * 16
|
||||
- Math.clamp(moisture, -1.0F, 1.0F) * 10;
|
||||
if (elevation < 112 && variation > 0.62F && moisture < -0.25F) return Kind.SULFUR_DEPTHS;
|
||||
// Preserve the strongest horizontal rock patches of alpha.6, with a smaller footprint.
|
||||
// Height alone never converts an otherwise forested mountain into exposed stone.
|
||||
if (variation > 0.48F) return Kind.ROCKY_HEATH;
|
||||
if (elevation < 214) {
|
||||
if (variation < -0.45F && moisture > 0.40F) return Kind.BAMBOO_GROVE;
|
||||
double shelteredMoisture = moisture + Math.min(0.55, (214 - elevation) / 160);
|
||||
if (shelteredMoisture > -0.08) return Kind.DARK_GROVE;
|
||||
}
|
||||
if (moisture < -0.55F && variation > -0.25F) return Kind.DRY_WOODLAND;
|
||||
if (Math.abs(variation) < 0.09F && moisture < 0.35F) return Kind.CLEARING;
|
||||
if (variation < -0.33F) return Kind.BIRCH_FOREST;
|
||||
return Kind.OAK_FOREST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
/** Natural supports and canopy space; independent of Minecraft blocks and decoration order. */
|
||||
public final class WoodlandGroveGeometry {
|
||||
@FunctionalInterface public interface Sampler { float sample(int x, int y, int z); }
|
||||
|
||||
private WoodlandGroveGeometry() {}
|
||||
|
||||
public static int highestSurface(Sampler sampler, int x, int z) {
|
||||
return highestSurfaceBelow(sampler, x, z, 383);
|
||||
}
|
||||
|
||||
/** The caller supplies a proven upper bound, including any removed natural surface. */
|
||||
public static int highestSurfaceBelow(Sampler sampler, int x, int z, int ceiling) {
|
||||
for (int y = Math.min(383, ceiling); y >= 24; y--) if (sampler.sample(x, y, z) > 0) return y;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean naturalFootprint(Sampler sampler, int x, int bedY, int z, int width) {
|
||||
if (bedY < 32 || bedY > 350) return false;
|
||||
for (int dx = 0; dx < width; dx++) for (int dz = 0; dz < width; dz++) {
|
||||
for (int dy = -2; dy <= 0; dy++) if (sampler.sample(x + dx, bedY + dy, z + dz) <= 0) return false;
|
||||
if (sampler.sample(x + dx, bedY + 1, z + dz) > 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean treeRoom(Sampler sampler, int x, int baseY, int z, int width, int radius, int height) {
|
||||
if (baseY + height >= 384) return false;
|
||||
for (int y = baseY; y <= baseY + height; y++) {
|
||||
int from = y < baseY + 3 ? 0 : -radius;
|
||||
int to = y < baseY + 3 ? width - 1 : radius;
|
||||
for (int dx = from; dx <= to; dx++) for (int dz = from; dz <= to; dz++) {
|
||||
if (sampler.sample(x + dx, y, z + dz) > 0) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static long seed(long worldSeed, int x, int y, int z, long salt) {
|
||||
long value = worldSeed ^ ((long) x << 32) ^ (z & 0xffffffffL) ^ y * 0x9e3779b97f4a7c15L ^ salt;
|
||||
value = (value ^ value >>> 30) * 0xbf58476d1ce4e5b9L;
|
||||
value = (value ^ value >>> 27) * 0x94d049bb133111ebL;
|
||||
return value ^ value >>> 31;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.WeakHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.worldgen.features.TreeFeatures;
|
||||
import net.minecraft.data.worldgen.features.VegetationFeatures;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.VegetationBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
|
||||
/** Alpha.7: real vanilla trees on natural lower floors, plus one globally selected remarkable tree.
|
||||
* Placement runs only in new generation. No world journal or mutable placement counter is retained. */
|
||||
public final class WoodlandGrovesFeature implements Feature {
|
||||
public static final MapCodec<WoodlandGrovesFeature> CODEC = MapCodec.unit(WoodlandGrovesFeature::new);
|
||||
private static final Map<RandomState, Optional<RemarkableTree>> REMARKABLE =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
public record RemarkableTree(BlockPos base, String featureId, int radius, int height) {
|
||||
public RemarkableTree { base = base.immutable(); }
|
||||
}
|
||||
private record Species(ResourceKey<Feature> key, int width, int radius, int height) {}
|
||||
private record Candidate(int x, int z, long rank) {}
|
||||
private static final Species CHERRY = new Species(TreeFeatures.CHERRY, 1, 9, 15);
|
||||
private static final Species[] SPECIES = {CHERRY, CHERRY, CHERRY, CHERRY,
|
||||
new Species(TreeFeatures.SPRUCE, 1, 5, 15), new Species(TreeFeatures.JUNGLE_TREE_NO_VINE, 1, 5, 14),
|
||||
new Species(TreeFeatures.ACACIA, 1, 7, 14), new Species(TreeFeatures.MANGROVE, 1, 10, 20),
|
||||
new Species(TreeFeatures.PALE_OAK_BONEMEAL, 2, 6, 12)};
|
||||
|
||||
@Override public MapCodec<WoodlandGrovesFeature> codec() { return CODEC; }
|
||||
|
||||
public static Optional<RemarkableTree> remarkablePlan(ServerLevel level) {
|
||||
if (!(level.getChunkSource().getGenerator() instanceof NoiseBasedChunkGenerator noise)) return Optional.empty();
|
||||
return remarkablePlan(noise, level.getChunkSource().randomState());
|
||||
}
|
||||
|
||||
public static Optional<RemarkableTree> remarkablePlan(NoiseBasedChunkGenerator noise, RandomState state) {
|
||||
if (!WoodlandHydrologyRuntime.enabled(noise)) return Optional.empty();
|
||||
return REMARKABLE.computeIfAbsent(state, ignored -> {
|
||||
var density = noise.generatorSettings().value().noiseRouter().finalDensity();
|
||||
WoodlandGroveGeometry.Sampler sampler = (x, y, z) -> state.sampleBlockValueUncached(density, x, y, z);
|
||||
var water = WoodlandHydrologyRuntime.plan(noise, state);
|
||||
var lava = WoodlandHydrologyRuntime.lavaPlan(noise, state);
|
||||
Species species = SPECIES[Math.floorMod(WoodlandGroveGeometry.seed(state.seed(), 0, 0, 0, 0x70EEL), SPECIES.length)];
|
||||
var candidates = new ArrayList<Candidate>();
|
||||
for (int x = -152; x <= 152; x += 16) for (int z = -152; z <= 152; z += 16) {
|
||||
if (Math.hypot(x, z) <= 168) candidates.add(new Candidate(x, z,
|
||||
WoodlandGroveGeometry.seed(state.seed(), x, 0, z, 0x71AFL)));
|
||||
}
|
||||
candidates.sort(Comparator.comparingLong(Candidate::rank).thenComparingInt(Candidate::x).thenComparingInt(Candidate::z));
|
||||
for (Candidate candidate : candidates) {
|
||||
int bed = WoodlandGroveGeometry.highestSurface(sampler, candidate.x(), candidate.z());
|
||||
if (!WoodlandGroveGeometry.naturalFootprint(sampler, candidate.x(), bed, candidate.z(), species.width())) continue;
|
||||
BlockPos base = new BlockPos(candidate.x(), bed + 1, candidate.z());
|
||||
if (blocked(water, lava, base, species.radius() + 1, species.height(), rootDepth(species))) continue;
|
||||
if (!WoodlandGroveGeometry.treeRoom(sampler, base.getX(), base.getY(), base.getZ(),
|
||||
species.width(), species.radius(), species.height())) continue;
|
||||
return Optional.of(new RemarkableTree(base, species.key().identifier().toString(), species.radius(), species.height()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(WorldGenLevel level, ChunkGenerator generator, RandomSource ignored, BlockPos origin) {
|
||||
if (!(generator instanceof NoiseBasedChunkGenerator noise) || !WoodlandHydrologyRuntime.enabled(noise)) return false;
|
||||
int minX = (origin.getX() >> 4) * 16, minZ = (origin.getZ() >> 4) * 16;
|
||||
if (Math.abs((long) minX) > 272 || Math.abs((long) minZ) > 272) return false;
|
||||
var state = level.getLevel().getChunkSource().randomState();
|
||||
var density = noise.generatorSettings().value().noiseRouter().finalDensity();
|
||||
WoodlandGroveGeometry.Sampler sampler = (x, y, z) -> state.sampleBlockValueUncached(density, x, y, z);
|
||||
var water = WoodlandHydrologyRuntime.plan(noise, state);
|
||||
var lava = WoodlandHydrologyRuntime.lavaPlan(noise, state);
|
||||
boolean changed = false;
|
||||
int[] heights = new int[256];
|
||||
Arrays.fill(heights, Integer.MIN_VALUE);
|
||||
var remarkable = remarkablePlan(noise, state);
|
||||
if (remarkable.isPresent()) {
|
||||
var tree = remarkable.get();
|
||||
BlockPos base = tree.base();
|
||||
if ((base.getX() >> 4) == (minX >> 4) && (base.getZ() >> 4) == (minZ >> 4)) {
|
||||
for (Species species : SPECIES) if (species.key().identifier().toString().equals(tree.featureId())) {
|
||||
changed |= tree(level, generator, sampler, state.seed(), base, species, water, lava, 0x723BL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Four spaced origins per chunk; the 2x2 trunk and full canopy still have to fit the cave.
|
||||
for (int x = minX + 4; x < minX + 16; x += 8) for (int z = minZ + 4; z < minZ + 16; z += 8) {
|
||||
int highest = localTop(level, sampler, water, minX, minZ, x, z, heights), placed = 0;
|
||||
for (int bed = highest - 8; bed >= 40; bed--) {
|
||||
BlockPos base = new BlockPos(x, bed + 1, z);
|
||||
if (!ground(level.getBlockState(base.below())) || !level.getBlockState(base).isAir()) continue;
|
||||
var biome = level.getBiome(base);
|
||||
boolean dark = biome.is(WoodlandIslandBiomeSource.DARK_GROVE);
|
||||
boolean bamboo = biome.is(WoodlandIslandBiomeSource.BAMBOO_GROVE);
|
||||
if (!dark && !bamboo) continue;
|
||||
long placementSeed = WoodlandGroveGeometry.seed(state.seed(), x, bed, z, 0x730DL);
|
||||
if (dark) {
|
||||
if (tree(level, generator, sampler, state.seed(), base,
|
||||
new Species(TreeFeatures.DARK_OAK, 2, 6, 12), water, lava, 0x730DL)) { changed = true; placed++; }
|
||||
} else if (Math.floorMod(placementSeed, 8) == 0) {
|
||||
if (tree(level, generator, sampler, state.seed(), base,
|
||||
new Species(TreeFeatures.JUNGLE_TREE_NO_VINE, 1, 5, 14), water, lava, 0x735BL)) { changed = true; placed++; }
|
||||
} else if (Math.floorMod(placementSeed, 3) == 0
|
||||
&& WoodlandGroveGeometry.naturalFootprint(sampler, x, bed, z, 1)
|
||||
&& WoodlandGroveGeometry.treeRoom(sampler, x, bed + 1, z, 1, 3, 16)
|
||||
&& !blocked(water, lava, base, 4, 17) && actualRoom(level, base, 1, 3, 16)) {
|
||||
setBlock(level, base.below(), Blocks.PODZOL.defaultBlockState());
|
||||
changed |= level.registryAccess().lookupOrThrow(Registries.FEATURE).getOrThrow(VegetationFeatures.BAMBOO_NO_PODZOL)
|
||||
.value().place(level, generator, RandomSource.create(placementSeed), base);
|
||||
placed++;
|
||||
}
|
||||
if (placed >= 2) break;
|
||||
}
|
||||
}
|
||||
// Ground cover uses coherent patches; mushrooms can survive on podzol/mycelium in shade.
|
||||
for (int x = minX; x < minX + 16; x++) for (int z = minZ; z < minZ + 16; z++) {
|
||||
int highest = localTop(level, sampler, water, minX, minZ, x, z, heights), floors = 0;
|
||||
for (int bed = highest - 8; bed >= 32; bed--) {
|
||||
BlockPos floor = new BlockPos(x, bed, z), plant = floor.above();
|
||||
if (!ground(level.getBlockState(floor)) || !level.getBlockState(plant).isAir()) continue;
|
||||
var biome = level.getBiome(plant);
|
||||
if (!biome.is(WoodlandIslandBiomeSource.DARK_GROVE) && !biome.is(WoodlandIslandBiomeSource.BAMBOO_GROVE)) continue;
|
||||
if (!WoodlandGroveGeometry.naturalFootprint(sampler, x, bed, z, 1) || blocked(water, lava, plant, 1, 2)) continue;
|
||||
long patch = WoodlandGroveGeometry.seed(state.seed(), Math.floorDiv(x, 7), 0, Math.floorDiv(z, 7), 0x742DL);
|
||||
BlockState soil = Math.floorMod(patch, 20) == 0 ? Blocks.MOSS_BLOCK.defaultBlockState()
|
||||
: Math.floorMod(patch, 3) == 0 ? Blocks.MYCELIUM.defaultBlockState() : Blocks.PODZOL.defaultBlockState();
|
||||
setBlock(level, floor, soil);
|
||||
long detail = WoodlandGroveGeometry.seed(state.seed(), x, bed, z, 0x743EL);
|
||||
if (Math.floorMod(detail, 5) == 0) {
|
||||
BlockState mushroom = (Math.floorMod(detail, 2) == 0 ? Blocks.BROWN_MUSHROOM : Blocks.RED_MUSHROOM).defaultBlockState();
|
||||
if (mushroom.canSurvive(level, plant)) setBlock(level, plant, mushroom);
|
||||
}
|
||||
changed = true;
|
||||
if (++floors >= 3) break;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private boolean tree(WorldGenLevel level, ChunkGenerator generator, WoodlandGroveGeometry.Sampler sampler, long seed,
|
||||
BlockPos base, Species species, LayeredHydrology.Plan water, LayeredLavaDeposit.Plan lava, long salt) {
|
||||
if (blocked(water, lava, base, species.radius() + 1, species.height(), rootDepth(species))
|
||||
|| !WoodlandGroveGeometry.naturalFootprint(sampler, base.getX(), base.getY() - 1, base.getZ(), species.width())
|
||||
|| !actualRoom(level, base, species.width(), species.radius(), species.height())
|
||||
|| !WoodlandGroveGeometry.treeRoom(sampler, base.getX(), base.getY(), base.getZ(), species.width(), species.radius(), species.height())) return false;
|
||||
for (int dx = 0; dx < species.width(); dx++) for (int dz = 0; dz < species.width(); dz++) {
|
||||
BlockPos floor = base.offset(dx, -1, dz);
|
||||
if (!ground(level.getBlockState(floor))) return false;
|
||||
}
|
||||
for (int dx = 0; dx < species.width(); dx++) for (int dz = 0; dz < species.width(); dz++) {
|
||||
setBlock(level, base.offset(dx, -1, dz), Blocks.PODZOL.defaultBlockState());
|
||||
}
|
||||
return level.registryAccess().lookupOrThrow(Registries.FEATURE).getOrThrow(species.key()).value()
|
||||
.place(level, generator, RandomSource.create(WoodlandGroveGeometry.seed(seed, base.getX(), base.getY(), base.getZ(), salt)), base);
|
||||
}
|
||||
|
||||
private static boolean actualRoom(WorldGenLevel level, BlockPos base, int width, int radius, int height) {
|
||||
for (int y = 0; y <= height; y++) {
|
||||
int from = y < 3 ? 0 : -radius, to = y < 3 ? width - 1 : radius;
|
||||
for (int dx = from; dx <= to; dx++) for (int dz = from; dz <= to; dz++) {
|
||||
BlockState current = level.getBlockState(base.offset(dx, y, dz));
|
||||
if (!current.getFluidState().isEmpty() || !(current.isAir() || current.is(BlockTags.LEAVES)
|
||||
|| current.getBlock() instanceof VegetationBlock)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean ground(BlockState state) {
|
||||
return state.is(Blocks.STONE) || state.is(Blocks.DIRT) || state.is(Blocks.GRASS_BLOCK) || state.is(Blocks.PODZOL)
|
||||
|| state.is(Blocks.MYCELIUM) || state.is(Blocks.ROOTED_DIRT) || state.is(Blocks.COARSE_DIRT)
|
||||
|| state.is(Blocks.GRANITE) || state.is(Blocks.DIORITE) || state.is(Blocks.ANDESITE) || state.is(Blocks.TUFF);
|
||||
}
|
||||
|
||||
private static int localTop(WorldGenLevel level, WoodlandGroveGeometry.Sampler sampler, LayeredHydrology.Plan water,
|
||||
int minX, int minZ, int x, int z, int[] heights) {
|
||||
int index = (x - minX) * 16 + z - minZ;
|
||||
if (heights[index] != Integer.MIN_VALUE) return heights[index];
|
||||
// This feature runs first in the vegetation step. Ores preserve the surface; hydrology
|
||||
// is the only preceding operation that removes it and records the original carveTop.
|
||||
int ceiling = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z) - 1;
|
||||
var modified = water.cellAt(x, z);
|
||||
if (modified != null) ceiling = Math.max(ceiling, modified.carveTop());
|
||||
return heights[index] = WoodlandGroveGeometry.highestSurfaceBelow(sampler, x, z, ceiling);
|
||||
}
|
||||
|
||||
private static int rootDepth(Species species) { return species.key().equals(TreeFeatures.MANGROVE) ? 16 : 4; }
|
||||
|
||||
private static boolean blocked(LayeredHydrology.Plan water, LayeredLavaDeposit.Plan lava, BlockPos base, int radius, int height) {
|
||||
return blocked(water, lava, base, radius, height, 4);
|
||||
}
|
||||
|
||||
private static boolean blocked(LayeredHydrology.Plan water, LayeredLavaDeposit.Plan lava, BlockPos base,
|
||||
int radius, int height, int rootDepth) {
|
||||
int low = base.getY() - rootDepth, high = base.getY() + height;
|
||||
for (int x = base.getX() - radius; x <= base.getX() + radius; x++) {
|
||||
for (int z = base.getZ() - radius; z <= base.getZ() + radius; z++) {
|
||||
var cell = water.cellAt(x, z);
|
||||
if (cell != null && low <= cell.carveTop() && high >= cell.bedY() - cell.sedimentDepth() - 1) return true;
|
||||
}
|
||||
}
|
||||
for (var spring : water.springs()) {
|
||||
var bounds = spring.flowBounds();
|
||||
if (base.getX() + radius >= bounds.minX() - 2 && base.getX() - radius <= bounds.maxX() + 2
|
||||
&& base.getZ() + radius >= bounds.minZ() - 2 && base.getZ() - radius <= bounds.maxZ() + 2
|
||||
&& low <= bounds.maxY() + 2 && high >= bounds.minY() - 2) return true;
|
||||
var source = spring.source();
|
||||
if (Math.abs(base.getX() - source.x()) <= radius + 3 && Math.abs(base.getZ() - source.z()) <= radius + 3
|
||||
&& low <= source.y() + 3 && high >= source.y() - 3) return true;
|
||||
}
|
||||
for (var cell : lava.cells()) if (Math.abs(base.getX() - cell.x()) <= radius + 2 && Math.abs(base.getZ() - cell.z()) <= radius + 2
|
||||
&& low <= cell.y() + 2 && high >= cell.y() - 2) return true;
|
||||
for (var support : lava.supports()) if (Math.abs(base.getX() - support.x()) <= radius + 2 && Math.abs(base.getZ() - support.z()) <= radius + 2
|
||||
&& low <= support.y() + 2 && high >= support.y() - 2) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import fr.koka.sanctuary.SanctuaryMod;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
|
||||
/** Alpha.7 only: immutable plans cached by world state, applied to fresh terrain before decoration. */
|
||||
public final class WoodlandHydrologyRuntime {
|
||||
private static final Map<RandomState, LayeredHydrology.Plan> PLANS =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
private static final Map<RandomState, LayeredLavaDeposit.Plan> LAVA_PLANS =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
private WoodlandHydrologyRuntime() {}
|
||||
|
||||
public static boolean enabled(NoiseBasedChunkGenerator generator) {
|
||||
return generator.generatorSettings().is(SanctuarySpawn.WOODLAND_SETTINGS);
|
||||
}
|
||||
|
||||
public static LayeredHydrology.Plan woodlandPlan(ServerLevel level) {
|
||||
return plan((NoiseBasedChunkGenerator) level.getChunkSource().getGenerator(),
|
||||
level.getChunkSource().randomState());
|
||||
}
|
||||
|
||||
public static LayeredHydrology.Plan plan(NoiseBasedChunkGenerator generator, RandomState randomState) {
|
||||
if (!enabled(generator)) throw new IllegalArgumentException("Woodland hydrology is not enabled for this generator");
|
||||
return PLANS.computeIfAbsent(randomState, state -> {
|
||||
long start = System.nanoTime();
|
||||
var density = generator.generatorSettings().value().noiseRouter().finalDensity();
|
||||
var plan = LayeredHydrology.create(state.seed(),
|
||||
(x, y, z) -> state.sampleBlockValueUncached(density, x, y, z));
|
||||
SanctuaryMod.LOGGER.info("Sanctuary woodland hydrology: seed {}, {} features, {} columns, {} springs, {} ms",
|
||||
state.seed(), plan.features().size(), plan.cells().size(), plan.springs().size(),
|
||||
(System.nanoTime() - start) / 1_000_000);
|
||||
return plan;
|
||||
});
|
||||
}
|
||||
|
||||
public static LayeredLavaDeposit.Plan lavaPlan(ServerLevel level) {
|
||||
return lavaPlan((NoiseBasedChunkGenerator) level.getChunkSource().getGenerator(),
|
||||
level.getChunkSource().randomState());
|
||||
}
|
||||
|
||||
public static LayeredLavaDeposit.Plan lavaPlan(NoiseBasedChunkGenerator generator, RandomState randomState) {
|
||||
// Acquire the water plan before the lava cache lock; the water planner never acquires it.
|
||||
var water = plan(generator, randomState);
|
||||
return LAVA_PLANS.computeIfAbsent(randomState, state -> {
|
||||
long start = System.nanoTime();
|
||||
var density = generator.generatorSettings().value().noiseRouter().finalDensity();
|
||||
var lava = LayeredLavaDeposit.create(state.seed(),
|
||||
(x, y, z) -> state.sampleBlockValueUncached(density, x, y, z), water);
|
||||
SanctuaryMod.LOGGER.info("Sanctuary starter lava: seed {}, {} sources, access {}, {} ms",
|
||||
state.seed(), lava.lavaCells().size(), lava.access(), (System.nanoTime() - start) / 1_000_000);
|
||||
return lava;
|
||||
});
|
||||
}
|
||||
|
||||
public static void apply(NoiseBasedChunkGenerator generator, RandomState randomState, ChunkAccess chunk) {
|
||||
if (!enabled(generator)) return;
|
||||
var chunkPos = chunk.getPos();
|
||||
if (Math.abs((long) chunkPos.x() * 16) > IslandShape.TERRAIN_LIMIT + 16L
|
||||
|| Math.abs((long) chunkPos.z() * 16) > IslandShape.TERRAIN_LIMIT + 16L) return;
|
||||
var plan = plan(generator, randomState);
|
||||
var cells = plan.cellsInChunk(chunkPos.x(), chunkPos.z());
|
||||
var springs = plan.springsInChunk(chunkPos.x(), chunkPos.z());
|
||||
var outlets = plan.springs().stream().map(LayeredHydrology.Spring::outlet)
|
||||
.filter(outlet -> (outlet.x() >> 4) == chunkPos.x() && (outlet.z() >> 4) == chunkPos.z()).toList();
|
||||
var lava = lavaPlan(generator, randomState);
|
||||
var lavaCells = lava.cellsInChunk(chunkPos.x(), chunkPos.z());
|
||||
var lavaSupports = lava.supportsInChunk(chunkPos.x(), chunkPos.z());
|
||||
if (cells.isEmpty() && springs.isEmpty() && outlets.isEmpty() && lavaCells.isEmpty() && lavaSupports.isEmpty()) return;
|
||||
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
// Validate all replacements and two intact support layers before modifying this chunk.
|
||||
for (var cell : cells) {
|
||||
for (int y = cell.bedY() - cell.sedimentDepth() - 1; y <= cell.bedY(); y++) {
|
||||
requireSolid(chunk, pos.set(cell.x(), y, cell.z()), randomState.seed());
|
||||
}
|
||||
}
|
||||
for (var spring : springs) {
|
||||
var source = spring.source();
|
||||
requireSolid(chunk, pos.set(source.x(), source.y(), source.z()), randomState.seed());
|
||||
}
|
||||
for (var support : lavaSupports) {
|
||||
requireSolid(chunk, pos.set(support.x(), support.y(), support.z()), randomState.seed());
|
||||
if (chunk.getBlockState(pos).ignitedByLava()) {
|
||||
throw new IllegalStateException("Lava pocket requires nonflammable natural support at " + pos);
|
||||
}
|
||||
}
|
||||
for (var cell : lavaCells) {
|
||||
requireSolid(chunk, pos.set(cell.x(), cell.y(), cell.z()), randomState.seed());
|
||||
}
|
||||
for (var cell : cells) {
|
||||
for (int depth = 0; depth < cell.sedimentDepth(); depth++) {
|
||||
pos.set(cell.x(), cell.bedY() - depth, cell.z());
|
||||
BlockState material = WoodlandMaterials.sedimentBlock(cell, randomState.seed(), depth);
|
||||
chunk.setBlockState(pos, material, 0);
|
||||
}
|
||||
for (int y = cell.bedY() + 1; y <= Math.max(cell.waterY(), cell.carveTop()); y++) {
|
||||
pos.set(cell.x(), y, cell.z());
|
||||
chunk.setBlockState(pos, cell.hasWater() && y <= cell.waterY()
|
||||
? Blocks.WATER.defaultBlockState() : Blocks.AIR.defaultBlockState(), 0);
|
||||
if (cell.hasWater() && y <= cell.waterY()) chunk.markPosForPostProcessing(pos);
|
||||
}
|
||||
}
|
||||
for (var spring : springs) {
|
||||
var source = spring.source();
|
||||
pos.set(source.x(), source.y(), source.z());
|
||||
chunk.setBlockState(pos, Blocks.WATER.defaultBlockState(), 0);
|
||||
// Only the source is generated. Vanilla fluid ticks create the descending waterfall.
|
||||
chunk.markPosForPostProcessing(pos);
|
||||
}
|
||||
for (var cell : lavaCells) {
|
||||
pos.set(cell.x(), cell.y(), cell.z());
|
||||
chunk.setBlockState(pos, (cell.lava() ? Blocks.LAVA : Blocks.AIR).defaultBlockState(), 0);
|
||||
if (cell.lava()) chunk.markPosForPostProcessing(pos);
|
||||
}
|
||||
// This existing vanilla queue is consumed after neighbouring chunks finish decoration.
|
||||
// Mark the outlet in its own chunk, including when its source belongs to a neighbour.
|
||||
for (var outlet : outlets) {
|
||||
pos.set(outlet.x(), outlet.y(), outlet.z());
|
||||
chunk.markPosForPostProcessing(pos);
|
||||
}
|
||||
Heightmap.primeHeightmaps(chunk, EnumSet.of(Heightmap.Types.WORLD_SURFACE_WG,
|
||||
Heightmap.Types.OCEAN_FLOOR_WG));
|
||||
}
|
||||
|
||||
private static void requireSolid(ChunkAccess chunk, BlockPos pos, long seed) {
|
||||
if (!chunk.getBlockState(pos).isCollisionShapeFullBlock(chunk, pos)) {
|
||||
throw new IllegalStateException("Woodland hydrology differs from terrain at " + pos + " for seed " + seed);
|
||||
}
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import fr.koka.sanctuary.SanctuaryMod;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeResolver;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
|
||||
/** Seeded alpha.7 woodland climate, separate from all saved earlier biome-source codecs. */
|
||||
public final class WoodlandIslandBiomeSource extends BiomeSource {
|
||||
public static final ResourceKey<Biome> OAK_FOREST = key("woodland_oak_forest");
|
||||
public static final ResourceKey<Biome> BIRCH_FOREST = key("woodland_birch_forest");
|
||||
public static final ResourceKey<Biome> CLEARING = key("woodland_clearing");
|
||||
public static final ResourceKey<Biome> DRY_WOODLAND = key("woodland_dry_woodland");
|
||||
public static final ResourceKey<Biome> ROCKY_HEATH = key("woodland_rocky_heath");
|
||||
public static final ResourceKey<Biome> DARK_GROVE = key("woodland_dark_grove");
|
||||
public static final ResourceKey<Biome> BAMBOO_GROVE = key("woodland_bamboo_grove");
|
||||
public static final ResourceKey<Biome> SULFUR_DEPTHS = key("woodland_sulfur_depths");
|
||||
|
||||
public static final MapCodec<WoodlandIslandBiomeSource> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Biome.CODEC.fieldOf("oak_forest").forGetter(source -> source.oakForest),
|
||||
Biome.CODEC.fieldOf("birch_forest").forGetter(source -> source.birchForest),
|
||||
Biome.CODEC.fieldOf("clearing").forGetter(source -> source.clearing),
|
||||
Biome.CODEC.fieldOf("dry_woodland").forGetter(source -> source.dryWoodland),
|
||||
Biome.CODEC.fieldOf("rocky_heath").forGetter(source -> source.rockyHeath),
|
||||
Biome.CODEC.fieldOf("dark_grove").forGetter(source -> source.darkGrove),
|
||||
Biome.CODEC.fieldOf("bamboo_grove").forGetter(source -> source.bambooGrove),
|
||||
Biome.CODEC.fieldOf("sulfur_depths").forGetter(source -> source.sulfurDepths)
|
||||
).apply(instance, WoodlandIslandBiomeSource::new));
|
||||
|
||||
private final Holder<Biome> oakForest;
|
||||
private final Holder<Biome> birchForest;
|
||||
private final Holder<Biome> clearing;
|
||||
private final Holder<Biome> dryWoodland;
|
||||
private final Holder<Biome> rockyHeath;
|
||||
private final Holder<Biome> darkGrove;
|
||||
private final Holder<Biome> bambooGrove;
|
||||
private final Holder<Biome> sulfurDepths;
|
||||
|
||||
public WoodlandIslandBiomeSource(Holder<Biome> oakForest, Holder<Biome> birchForest, Holder<Biome> clearing,
|
||||
Holder<Biome> dryWoodland, Holder<Biome> rockyHeath, Holder<Biome> darkGrove,
|
||||
Holder<Biome> bambooGrove, Holder<Biome> sulfurDepths) {
|
||||
this.oakForest = oakForest;
|
||||
this.birchForest = birchForest;
|
||||
this.clearing = clearing;
|
||||
this.dryWoodland = dryWoodland;
|
||||
this.rockyHeath = rockyHeath;
|
||||
this.darkGrove = darkGrove;
|
||||
this.bambooGrove = bambooGrove;
|
||||
this.sulfurDepths = sulfurDepths;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapCodec<WoodlandIslandBiomeSource> codec() { return CODEC; }
|
||||
|
||||
@Override
|
||||
protected Stream<Holder<Biome>> collectPossibleBiomes() {
|
||||
return Stream.of(oakForest, birchForest, clearing, dryWoodland, rockyHeath, darkGrove, bambooGrove, sulfurDepths);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeResolver createResolver(Climate.Sampler sampler) {
|
||||
return (quartX, quartY, quartZ) -> {
|
||||
int x = quartX * 4, y = quartY * 4, z = quartZ * 4;
|
||||
float variation = sampler.temperature().sampleValue(x, 0, z);
|
||||
float moisture = sampler.humidity().sampleValue(x, 0, z);
|
||||
return switch (WoodlandBiomePalette.select(y, variation, moisture)) {
|
||||
case OAK_FOREST -> oakForest;
|
||||
case BIRCH_FOREST -> birchForest;
|
||||
case CLEARING -> clearing;
|
||||
case DRY_WOODLAND -> dryWoodland;
|
||||
case ROCKY_HEATH -> rockyHeath;
|
||||
case DARK_GROVE -> darkGrove;
|
||||
case BAMBOO_GROVE -> bambooGrove;
|
||||
case SULFUR_DEPTHS -> sulfurDepths;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private static ResourceKey<Biome> key(String path) {
|
||||
return ResourceKey.create(Registries.BIOME, SanctuaryMod.id(path));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/** Alpha.7 shore deposits: broad continuous patches through the existing sediment thickness. */
|
||||
public final class WoodlandMaterials {
|
||||
private WoodlandMaterials() {}
|
||||
|
||||
public static BlockState sedimentBlock(LayeredHydrology.Cell cell, long seed, int depth) {
|
||||
if (cell.material() == LayeredHydrology.ShoreMaterial.GRASS) {
|
||||
return (depth == 0 ? Blocks.GRASS_BLOCK : Blocks.DIRT).defaultBlockState();
|
||||
}
|
||||
double patch = patch(seed, cell.x(), cell.z(), 32);
|
||||
Block material;
|
||||
if (cell.hasWater() && patch < 0.24) material = Blocks.CLAY;
|
||||
else if (patch < 0.53) material = Blocks.SAND;
|
||||
else if (patch < 0.68) material = Blocks.GRAVEL;
|
||||
else {
|
||||
double rock = patch(seed ^ 0x4c6179657273L, cell.x(), cell.z(), 40);
|
||||
material = rock < 0.28 ? Blocks.GRANITE : rock < 0.45 ? Blocks.DIORITE
|
||||
: rock < 0.65 ? Blocks.ANDESITE : Blocks.STONE;
|
||||
}
|
||||
return material.defaultBlockState();
|
||||
}
|
||||
|
||||
private static double patch(long seed, int x, int z, int scale) {
|
||||
int gx = Math.floorDiv(x, scale), gz = Math.floorDiv(z, scale);
|
||||
double tx = smooth(Math.floorMod(x, scale) / (double) scale);
|
||||
double tz = smooth(Math.floorMod(z, scale) / (double) scale);
|
||||
double near = lerp(value(seed, gx, gz), value(seed, gx + 1, gz), tx);
|
||||
double far = lerp(value(seed, gx, gz + 1), value(seed, gx + 1, gz + 1), tx);
|
||||
return lerp(near, far, tz);
|
||||
}
|
||||
|
||||
private static double value(long seed, int x, int z) {
|
||||
return (WoodlandGroveGeometry.seed(seed, x, 0, z, 0x53484f5245L) >>> 11) * 0x1.0p-53;
|
||||
}
|
||||
|
||||
private static double smooth(double t) { return t * t * (3 - 2 * t); }
|
||||
private static double lerp(double a, double b, double t) { return a + (b - a) * t; }
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
|
||||
/** A few plants on existing suitable shores, after the forest has been decorated. */
|
||||
public final class WoodlandShoreSugarCaneFeature implements Feature {
|
||||
public static final MapCodec<WoodlandShoreSugarCaneFeature> CODEC = MapCodec.unit(WoodlandShoreSugarCaneFeature::new);
|
||||
|
||||
@Override
|
||||
public MapCodec<WoodlandShoreSugarCaneFeature> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean place(WorldGenLevel level, ChunkGenerator generator, RandomSource random, BlockPos origin) {
|
||||
if (!(generator instanceof NoiseBasedChunkGenerator noise) || !WoodlandHydrologyRuntime.enabled(noise)) return false;
|
||||
var plan = WoodlandHydrologyRuntime.plan(noise, level.getLevel().getChunkSource().randomState());
|
||||
var cane = Blocks.SUGAR_CANE.defaultBlockState();
|
||||
boolean placed = false;
|
||||
for (var cell : plan.cellsInChunk(origin.getX() >> 4, origin.getZ() >> 4)) {
|
||||
if (cell.hasWater() || random.nextInt(7) != 0) continue;
|
||||
BlockPos base = new BlockPos(cell.x(), cell.bedY() + 1, cell.z());
|
||||
if (!level.getBlockState(base).isAir() || !cane.canSurvive(level, base)) continue;
|
||||
int height = 1 + random.nextInt(3);
|
||||
for (int y = 0; y < height; y++) {
|
||||
BlockPos pos = base.above(y);
|
||||
if (!level.getBlockState(pos).isAir() || !cane.canSurvive(level, pos)) break;
|
||||
setBlock(level, pos, cane);
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
return placed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.VegetationBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
/** One-time alpha.7 outlet finishing, using vanilla's persisted and consumed generation queue. */
|
||||
public final class WoodlandSpringOutlets {
|
||||
public record Pending(List<LayeredHydrology.Position> sources, List<LayeredHydrology.Position> outlets) {
|
||||
public static final Pending EMPTY = new Pending(List.of(), List.of());
|
||||
public Pending { sources = List.copyOf(sources); outlets = List.copyOf(outlets); }
|
||||
public boolean isEmpty() { return sources.isEmpty() && outlets.isEmpty(); }
|
||||
}
|
||||
|
||||
private WoodlandSpringOutlets() {}
|
||||
|
||||
/** Called before vanilla consumes the queue; a fully processed/reloaded chunk has no work. */
|
||||
public static Pending capturePending(ServerLevel level, LevelChunk chunk) {
|
||||
if (!(level.getChunkSource().getGenerator() instanceof NoiseBasedChunkGenerator noise)
|
||||
|| !WoodlandHydrologyRuntime.enabled(noise)) return Pending.EMPTY;
|
||||
boolean queued = false;
|
||||
for (var section : chunk.getPostProcessing()) if (section != null && !section.isEmpty()) {
|
||||
queued = true;
|
||||
break;
|
||||
}
|
||||
if (!queued) return Pending.EMPTY;
|
||||
var plan = WoodlandHydrologyRuntime.plan(noise, level.getChunkSource().randomState());
|
||||
List<LayeredHydrology.Position> sources = new ArrayList<>(), outlets = new ArrayList<>();
|
||||
for (var spring : plan.springs()) {
|
||||
if (markedHere(chunk, spring.source())) sources.add(spring.source());
|
||||
if (markedHere(chunk, spring.outlet())) outlets.add(spring.outlet());
|
||||
}
|
||||
return new Pending(sources, outlets);
|
||||
}
|
||||
|
||||
/** All neighbouring FEATURES have finished before a chunk reaches this stage. */
|
||||
public static void finish(ServerLevel level, LevelChunk chunk, Pending pending) {
|
||||
if (pending.isEmpty() || !(level.getChunkSource().getGenerator() instanceof NoiseBasedChunkGenerator noise)
|
||||
|| !WoodlandHydrologyRuntime.enabled(noise)) return;
|
||||
var random = level.getChunkSource().randomState();
|
||||
var density = noise.generatorSettings().value().noiseRouter().finalDensity();
|
||||
for (var outlet : pending.outlets()) {
|
||||
if (!owns(chunk, outlet)) throw new IllegalArgumentException("An outlet belongs to another chunk: " + outlet);
|
||||
if (random.sampleBlockValueUncached(density, outlet.x(), outlet.y(), outlet.z()) > 0) {
|
||||
throw new IllegalStateException("A spring outlet must already be natural air: " + outlet);
|
||||
}
|
||||
BlockPos pos = blockPos(outlet);
|
||||
BlockState current = chunk.getBlockState(pos);
|
||||
if (removableDecoration(current)) {
|
||||
// Only this declared air cell is reopened. Neighbour notification wakes the
|
||||
// adjacent source even if its own chunk was post-processed first.
|
||||
level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
|
||||
}
|
||||
}
|
||||
for (var source : pending.sources()) {
|
||||
if (!owns(chunk, source)) throw new IllegalArgumentException("A source belongs to another chunk: " + source);
|
||||
BlockPos pos = blockPos(source);
|
||||
BlockState current = chunk.getBlockState(pos);
|
||||
if (current.is(Blocks.WATER) && current.getFluidState().isSource()) {
|
||||
level.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean markedHere(LevelChunk chunk, LayeredHydrology.Position position) {
|
||||
if (!owns(chunk, position)) return false;
|
||||
var queue = chunk.getPostProcessing()[chunk.getSectionIndex(position.y())];
|
||||
return queue != null && queue.contains(ProtoChunk.packOffsetCoordinates(blockPos(position)));
|
||||
}
|
||||
|
||||
private static boolean owns(LevelChunk chunk, LayeredHydrology.Position position) {
|
||||
return (position.x() >> 4) == chunk.getPos().x() && (position.z() >> 4) == chunk.getPos().z();
|
||||
}
|
||||
|
||||
private static BlockPos blockPos(LayeredHydrology.Position position) {
|
||||
return new BlockPos(position.x(), position.y(), position.z());
|
||||
}
|
||||
|
||||
private static boolean removableDecoration(BlockState state) {
|
||||
if (state.hasBlockEntity()) return false;
|
||||
return state.is(Blocks.GLOW_LICHEN) || state.is(Blocks.VINE) || state.is(Blocks.MOSS_CARPET)
|
||||
|| state.getBlock() instanceof VegetationBlock || state.is(BlockTags.LEAVES) || state.is(BlockTags.LOGS);
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,13 @@
|
||||
"biome.sanctuary.layered_flower_meadow": "Flowered Highland Meadow",
|
||||
"biome.sanctuary.layered_lower_grove": "Ledge Woodland",
|
||||
"biome.sanctuary.layered_mossy_terraces": "Mossy Ledges",
|
||||
"biome.sanctuary.layered_rocky_terraces": "Rocky Terraces"
|
||||
"biome.sanctuary.layered_rocky_terraces": "Rocky Terraces",
|
||||
"biome.sanctuary.woodland_oak_forest": "Sanctuary Oak Woodland",
|
||||
"biome.sanctuary.woodland_birch_forest": "Sanctuary Birch Woodland",
|
||||
"biome.sanctuary.woodland_clearing": "Flowered Clearing",
|
||||
"biome.sanctuary.woodland_dry_woodland": "Dry Woodland",
|
||||
"biome.sanctuary.woodland_rocky_heath": "Rocky Heath",
|
||||
"biome.sanctuary.woodland_dark_grove": "Dark Undergrowth",
|
||||
"biome.sanctuary.woodland_bamboo_grove": "Bamboo Grove",
|
||||
"biome.sanctuary.woodland_sulfur_depths": "Sulfur Depths"
|
||||
}
|
||||
|
||||
@@ -11,5 +11,13 @@
|
||||
"biome.sanctuary.layered_flower_meadow": "Prairie fleurie des hauteurs",
|
||||
"biome.sanctuary.layered_lower_grove": "Sous-bois des corniches",
|
||||
"biome.sanctuary.layered_mossy_terraces": "Corniches moussues",
|
||||
"biome.sanctuary.layered_rocky_terraces": "Terrasses rocheuses"
|
||||
"biome.sanctuary.layered_rocky_terraces": "Terrasses rocheuses",
|
||||
"biome.sanctuary.woodland_oak_forest": "Chênaie de Sanctuary",
|
||||
"biome.sanctuary.woodland_birch_forest": "Bétulaie de Sanctuary",
|
||||
"biome.sanctuary.woodland_clearing": "Clairière fleurie",
|
||||
"biome.sanctuary.woodland_dry_woodland": "Bois sec",
|
||||
"biome.sanctuary.woodland_rocky_heath": "Lande rocheuse",
|
||||
"biome.sanctuary.woodland_dark_grove": "Sous-bois sombre",
|
||||
"biome.sanctuary.woodland_bamboo_grove": "Bosquet de bambous",
|
||||
"biome.sanctuary.woodland_sulfur_depths": "Profondeurs soufrées"
|
||||
}
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.sparse_jungle"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": 4,
|
||||
"weight": 12
|
||||
},
|
||||
{
|
||||
"type": "minecraft:pig",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:cow",
|
||||
"count": 4,
|
||||
"weight": 8
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:wolf",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 2
|
||||
},
|
||||
"weight": 8
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.95,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:brown_mushroom_normal",
|
||||
"minecraft:red_mushroom_normal",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.8
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.forest"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": 4,
|
||||
"weight": 12
|
||||
},
|
||||
{
|
||||
"type": "minecraft:pig",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:cow",
|
||||
"count": 4,
|
||||
"weight": 8
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.7,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:forest_flowers",
|
||||
"minecraft:wildflowers_birch_forest",
|
||||
"minecraft:trees_birch",
|
||||
"minecraft:patch_bush",
|
||||
"minecraft:flower_default",
|
||||
"minecraft:patch_grass_forest",
|
||||
"minecraft:brown_mushroom_normal",
|
||||
"minecraft:red_mushroom_normal",
|
||||
"minecraft:patch_pumpkin",
|
||||
"minecraft:patch_sugar_cane",
|
||||
"minecraft:patch_firefly_bush_near_water",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.7
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.meadow"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:donkey",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 2,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"type": "minecraft:rabbit",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 2
|
||||
},
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 2
|
||||
},
|
||||
"weight": 2
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.75,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:patch_tall_grass_2",
|
||||
"minecraft:patch_grass_meadow",
|
||||
"minecraft:flower_meadow",
|
||||
"minecraft:trees_meadow",
|
||||
"minecraft:wildflowers_meadow",
|
||||
"minecraft:flower_flower_forest",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.7
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.forest"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": 4,
|
||||
"weight": 12
|
||||
},
|
||||
{
|
||||
"type": "minecraft:pig",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:cow",
|
||||
"count": 4,
|
||||
"weight": 8
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.9,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:brown_mushroom_normal",
|
||||
"minecraft:red_mushroom_normal",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.7
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.forest"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": 4,
|
||||
"weight": 12
|
||||
},
|
||||
{
|
||||
"type": "minecraft:pig",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:cow",
|
||||
"count": 4,
|
||||
"weight": 8
|
||||
},
|
||||
{
|
||||
"type": "minecraft:wolf",
|
||||
"count": 4,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.4,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:forest_flowers",
|
||||
"sanctuary:woodland_sparse_trees",
|
||||
"minecraft:patch_bush",
|
||||
"minecraft:flower_default",
|
||||
"minecraft:patch_grass_forest",
|
||||
"minecraft:brown_mushroom_normal",
|
||||
"minecraft:red_mushroom_normal",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.75
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.forest"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": 4,
|
||||
"weight": 12
|
||||
},
|
||||
{
|
||||
"type": "minecraft:pig",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:cow",
|
||||
"count": 4,
|
||||
"weight": 8
|
||||
},
|
||||
{
|
||||
"type": "minecraft:wolf",
|
||||
"count": 4,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.8,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"minecraft:forest_flowers",
|
||||
"minecraft:trees_birch_and_oak_leaf_litter",
|
||||
"minecraft:patch_bush",
|
||||
"minecraft:flower_default",
|
||||
"minecraft:patch_grass_forest",
|
||||
"minecraft:brown_mushroom_normal",
|
||||
"minecraft:red_mushroom_normal",
|
||||
"minecraft:patch_pumpkin",
|
||||
"minecraft:patch_sugar_cane",
|
||||
"minecraft:patch_firefly_bush_near_water",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.7
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.meadow"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:donkey",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 2,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"type": "minecraft:rabbit",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 2
|
||||
},
|
||||
"weight": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 2
|
||||
},
|
||||
"weight": 2
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.65,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.7
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"attributes": {
|
||||
"minecraft:audio/background_music": {
|
||||
"default": {
|
||||
"max_delay": 24000,
|
||||
"min_delay": 12000,
|
||||
"sound": "minecraft:music.overworld.forest"
|
||||
}
|
||||
},
|
||||
"minecraft:gameplay/natural_mob_spawns": {
|
||||
"argument": {
|
||||
"spawn_costs": {},
|
||||
"spawns_by_category": {
|
||||
"ambient": [
|
||||
{
|
||||
"type": "minecraft:bat",
|
||||
"count": 8,
|
||||
"weight": 10
|
||||
}
|
||||
],
|
||||
"creature": [
|
||||
{
|
||||
"type": "minecraft:sheep",
|
||||
"count": 4,
|
||||
"weight": 12
|
||||
},
|
||||
{
|
||||
"type": "minecraft:pig",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:chicken",
|
||||
"count": 4,
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:cow",
|
||||
"count": 4,
|
||||
"weight": 8
|
||||
},
|
||||
{
|
||||
"type": "minecraft:wolf",
|
||||
"count": 4,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"monster": [
|
||||
{
|
||||
"type": "minecraft:spider",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie",
|
||||
"count": 4,
|
||||
"weight": 95
|
||||
},
|
||||
{
|
||||
"type": "minecraft:zombie_villager",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
},
|
||||
{
|
||||
"type": "minecraft:skeleton",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:creeper",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:slime",
|
||||
"count": 4,
|
||||
"weight": 100
|
||||
},
|
||||
{
|
||||
"type": "minecraft:enderman",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 4,
|
||||
"min_inclusive": 1
|
||||
},
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:witch",
|
||||
"count": 1,
|
||||
"weight": 5
|
||||
}
|
||||
],
|
||||
"underground_water_creature": [
|
||||
{
|
||||
"type": "minecraft:glow_squid",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max_inclusive": 6,
|
||||
"min_inclusive": 4
|
||||
},
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"modifier": "overlay"
|
||||
},
|
||||
"minecraft:visual/sky_color": "#79a6ff"
|
||||
},
|
||||
"carvers": [],
|
||||
"downfall": 0.5,
|
||||
"effects": {
|
||||
"water_color": "#3f76e4",
|
||||
"grass_color": "#88b96b",
|
||||
"foliage_color": "#79aa61",
|
||||
"dry_foliage_color": "#b9a766"
|
||||
},
|
||||
"features": [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"minecraft:ore_dirt",
|
||||
"minecraft:ore_granite_upper",
|
||||
"minecraft:ore_granite_lower",
|
||||
"minecraft:ore_diorite_upper",
|
||||
"minecraft:ore_diorite_lower",
|
||||
"minecraft:ore_andesite_upper",
|
||||
"minecraft:ore_andesite_lower",
|
||||
"minecraft:ore_tuff",
|
||||
"sanctuary:woodland_ore_coal",
|
||||
"sanctuary:woodland_ore_iron",
|
||||
"sanctuary:woodland_ore_copper",
|
||||
"sanctuary:island_ore_gold",
|
||||
"sanctuary:island_ore_redstone",
|
||||
"sanctuary:island_ore_lapis",
|
||||
"sanctuary:island_ore_diamond",
|
||||
"sanctuary:woodland_ore_coal_surface",
|
||||
"sanctuary:woodland_ore_iron_surface",
|
||||
"sanctuary:woodland_ore_copper_surface",
|
||||
"sanctuary:woodland_ore_coal_ledges",
|
||||
"sanctuary:woodland_ore_iron_ledges",
|
||||
"sanctuary:woodland_ore_copper_ledges"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"sanctuary:woodland_groves",
|
||||
"minecraft:glow_lichen",
|
||||
"sanctuary:woodland_shore_sugar_cane"
|
||||
],
|
||||
[
|
||||
"minecraft:freeze_top_layer"
|
||||
]
|
||||
],
|
||||
"has_precipitation": true,
|
||||
"temperature": 0.8
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"type": "minecraft:ore",
|
||||
"discard_chance_on_air_exposure": 0.0,
|
||||
"size": 6,
|
||||
"targets": [
|
||||
{
|
||||
"state": "minecraft:coal_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
},
|
||||
{
|
||||
"max_inclusive": 2031,
|
||||
"min_inclusive": 0,
|
||||
"predicate_type": "minecraft:height_match"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:not",
|
||||
"rule": {
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:stone_ore_replaceables"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"state": "minecraft:deepslate_coal_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
},
|
||||
{
|
||||
"max_inclusive": 8,
|
||||
"min_inclusive": -2032,
|
||||
"predicate_type": "minecraft:height_match"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:not",
|
||||
"rule": {
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:deepslate_ore_replaceables"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"type": "minecraft:ore",
|
||||
"discard_chance_on_air_exposure": 0.0,
|
||||
"size": 5,
|
||||
"targets": [
|
||||
{
|
||||
"state": "minecraft:copper_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
},
|
||||
{
|
||||
"max_inclusive": 2031,
|
||||
"min_inclusive": 0,
|
||||
"predicate_type": "minecraft:height_match"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:not",
|
||||
"rule": {
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:stone_ore_replaceables"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"state": "minecraft:deepslate_copper_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
},
|
||||
{
|
||||
"max_inclusive": 8,
|
||||
"min_inclusive": -2032,
|
||||
"predicate_type": "minecraft:height_match"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:not",
|
||||
"rule": {
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:deepslate_ore_replaceables"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"type": "minecraft:ore",
|
||||
"discard_chance_on_air_exposure": 0.0,
|
||||
"size": 5,
|
||||
"targets": [
|
||||
{
|
||||
"state": "minecraft:iron_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
},
|
||||
{
|
||||
"max_inclusive": 2031,
|
||||
"min_inclusive": 0,
|
||||
"predicate_type": "minecraft:height_match"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:not",
|
||||
"rule": {
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:stone_ore_replaceables"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"state": "minecraft:deepslate_iron_ore",
|
||||
"target": {
|
||||
"predicate_type": "minecraft:any_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
},
|
||||
{
|
||||
"max_inclusive": 8,
|
||||
"min_inclusive": -2032,
|
||||
"predicate_type": "minecraft:height_match"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:all_of",
|
||||
"rules": [
|
||||
{
|
||||
"predicate_type": "minecraft:not",
|
||||
"rule": {
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:height_specific_ore_replaceables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"predicate_type": "minecraft:tag_match",
|
||||
"tag": "minecraft:deepslate_ore_replaceables"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"type": "minecraft:sequence",
|
||||
"sequence": [
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:biome",
|
||||
"biome_is": "sanctuary:woodland_sulfur_depths"
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "sanctuary:woodland_strata",
|
||||
"min_threshold": 0.0,
|
||||
"max_threshold": 1000,
|
||||
"is_3d": true
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": "minecraft:sulfur"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:biome",
|
||||
"biome_is": "sanctuary:woodland_rocky_heath"
|
||||
},
|
||||
"then_run": "sanctuary:woodland_strata"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "sanctuary:woodland_exposure",
|
||||
"min_threshold": 0.85,
|
||||
"max_threshold": 1000,
|
||||
"is_3d": false
|
||||
},
|
||||
"then_run": "sanctuary:woodland_strata"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:biome",
|
||||
"biome_is": "sanctuary:woodland_dry_woodland"
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "sanctuary:woodland_exposure",
|
||||
"min_threshold": 0.15,
|
||||
"max_threshold": 1000,
|
||||
"is_3d": false
|
||||
},
|
||||
"then_run": "sanctuary:woodland_strata"
|
||||
}
|
||||
},
|
||||
"sanctuary:starter_island",
|
||||
"sanctuary:woodland_strata"
|
||||
]
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"type": "minecraft:sequence",
|
||||
"sequence": [
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "sanctuary:woodland_strata",
|
||||
"min_threshold": -1000,
|
||||
"max_threshold": -0.36,
|
||||
"is_3d": true
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": "minecraft:granite"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "sanctuary:woodland_strata",
|
||||
"min_threshold": 0.36,
|
||||
"max_threshold": 1000,
|
||||
"is_3d": true
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": "minecraft:diorite"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "sanctuary:woodland_strata",
|
||||
"min_threshold": -0.14,
|
||||
"max_threshold": 0.14,
|
||||
"is_3d": true
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": "minecraft:andesite"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"result_state": "minecraft:stone"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"base_amplitude": 1.0,
|
||||
"base_octave": -7,
|
||||
"octave_count": 2
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"base_amplitude": 1.0,
|
||||
"base_octave": -6,
|
||||
"octave_count": 2
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"default_block": "minecraft:stone",
|
||||
"default_fluid": "minecraft:air",
|
||||
"disable_mob_generation": false,
|
||||
"legacy_random_source": true,
|
||||
"material_rule": "sanctuary:woodland_island",
|
||||
"noise": {
|
||||
"height": 384,
|
||||
"min_y": 0
|
||||
},
|
||||
"noise_router": {
|
||||
"chunk_surface_level": 0.0,
|
||||
"continents": 0.0,
|
||||
"depth": 0.0,
|
||||
"erosion": 0.0,
|
||||
"final_density": "sanctuary:final_density_384",
|
||||
"ridges": 0.0,
|
||||
"temperature": "sanctuary:temperate_variation",
|
||||
"vegetation": "sanctuary:temperate_moisture"
|
||||
},
|
||||
"sea_level": -64,
|
||||
"spawn_target": []
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"feature": {
|
||||
"type": "sanctuary:woodland_groves"
|
||||
},
|
||||
"placement": []
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_coal",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:trapezoid",
|
||||
"min_inclusive": {
|
||||
"absolute": 96
|
||||
},
|
||||
"max_inclusive": {
|
||||
"absolute": 288
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_coal",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:rarity_filter",
|
||||
"chance": 3
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:uniform",
|
||||
"min_inclusive": {
|
||||
"absolute": 48
|
||||
},
|
||||
"max_inclusive": {
|
||||
"absolute": 272
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block_predicate_filter",
|
||||
"predicate": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:air"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:environment_scan",
|
||||
"direction_of_search": "down",
|
||||
"max_steps": 32,
|
||||
"target_condition": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:stone_ore_replaceables"
|
||||
},
|
||||
"allowed_search_condition": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:air"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:offset",
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"z": 0
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_coal",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:rarity_filter",
|
||||
"chance": 3
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:heightmap",
|
||||
"heightmap": "OCEAN_FLOOR_WG"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block_predicate_filter",
|
||||
"predicate": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:stone_ore_replaceables",
|
||||
"offset": [
|
||||
0,
|
||||
-1,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_copper",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:trapezoid",
|
||||
"min_inclusive": {
|
||||
"absolute": 96
|
||||
},
|
||||
"max_inclusive": {
|
||||
"absolute": 288
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_copper",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:rarity_filter",
|
||||
"chance": 4
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:uniform",
|
||||
"min_inclusive": {
|
||||
"absolute": 48
|
||||
},
|
||||
"max_inclusive": {
|
||||
"absolute": 272
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block_predicate_filter",
|
||||
"predicate": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:air"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:environment_scan",
|
||||
"direction_of_search": "down",
|
||||
"max_steps": 32,
|
||||
"target_condition": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:stone_ore_replaceables"
|
||||
},
|
||||
"allowed_search_condition": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:air"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:offset",
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"z": 0
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_copper",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:rarity_filter",
|
||||
"chance": 4
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:heightmap",
|
||||
"heightmap": "OCEAN_FLOOR_WG"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block_predicate_filter",
|
||||
"predicate": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:stone_ore_replaceables",
|
||||
"offset": [
|
||||
0,
|
||||
-1,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_iron",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:trapezoid",
|
||||
"min_inclusive": {
|
||||
"absolute": 88
|
||||
},
|
||||
"max_inclusive": {
|
||||
"absolute": 288
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_iron",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:rarity_filter",
|
||||
"chance": 4
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:height_range",
|
||||
"height": {
|
||||
"type": "minecraft:uniform",
|
||||
"min_inclusive": {
|
||||
"absolute": 48
|
||||
},
|
||||
"max_inclusive": {
|
||||
"absolute": 272
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block_predicate_filter",
|
||||
"predicate": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:air"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:environment_scan",
|
||||
"direction_of_search": "down",
|
||||
"max_steps": 32,
|
||||
"target_condition": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:stone_ore_replaceables"
|
||||
},
|
||||
"allowed_search_condition": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:air"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:offset",
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"z": 0
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"feature": "sanctuary:woodland_ore_iron",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:rarity_filter",
|
||||
"chance": 4
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:heightmap",
|
||||
"heightmap": "OCEAN_FLOOR_WG"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:block_predicate_filter",
|
||||
"predicate": {
|
||||
"type": "minecraft:matching_block_tag",
|
||||
"tag": "minecraft:stone_ore_replaceables",
|
||||
"offset": [
|
||||
0,
|
||||
-1,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"feature": {
|
||||
"type": "sanctuary:woodland_shore_sugar_cane"
|
||||
},
|
||||
"placement": []
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"feature": "minecraft:trees_birch_and_oak_leaf_litter",
|
||||
"placement": [
|
||||
{
|
||||
"type": "minecraft:count",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"type": "minecraft:in_square"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:surface_water_depth_filter",
|
||||
"max_water_depth": 0
|
||||
},
|
||||
{
|
||||
"type": "minecraft:heightmap",
|
||||
"heightmap": "OCEAN_FLOOR"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:biome"
|
||||
}
|
||||
]
|
||||
}
|
||||
+10
-7
@@ -5,14 +5,17 @@
|
||||
"generator": {
|
||||
"type": "minecraft:noise",
|
||||
"biome_source": {
|
||||
"type": "sanctuary:layered_island",
|
||||
"meadow": "sanctuary:layered_meadow",
|
||||
"flower_meadow": "sanctuary:layered_flower_meadow",
|
||||
"lower_grove": "sanctuary:layered_lower_grove",
|
||||
"mossy_terraces": "sanctuary:layered_mossy_terraces",
|
||||
"rocky_terraces": "sanctuary:layered_rocky_terraces"
|
||||
"type": "sanctuary:woodland_island",
|
||||
"oak_forest": "sanctuary:woodland_oak_forest",
|
||||
"birch_forest": "sanctuary:woodland_birch_forest",
|
||||
"clearing": "sanctuary:woodland_clearing",
|
||||
"dry_woodland": "sanctuary:woodland_dry_woodland",
|
||||
"dark_grove": "sanctuary:woodland_dark_grove",
|
||||
"bamboo_grove": "sanctuary:woodland_bamboo_grove",
|
||||
"sulfur_depths": "sanctuary:woodland_sulfur_depths",
|
||||
"rocky_heath": "sanctuary:woodland_rocky_heath"
|
||||
},
|
||||
"settings": "sanctuary:sanctuary_layered"
|
||||
"settings": "sanctuary:sanctuary_woodland"
|
||||
}
|
||||
},
|
||||
"minecraft:the_end": {
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"mixins": [
|
||||
"InitialSpawnMixin",
|
||||
"SurfaceHydrologyMixin",
|
||||
"LayeredSpringOutletMixin"
|
||||
"LayeredSpringOutletMixin",
|
||||
"WoodlandSpringOutletMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.SanctuarySkyMixin",
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
public final class WoodlandGroveSmoke {
|
||||
public static void main(String[] args) {
|
||||
WoodlandGroveGeometry.Sampler cave = (x,y,z) -> y >= 80 && y <= 100 || y >= 120 && y <= 130 ? 1 : -1;
|
||||
require(WoodlandGroveGeometry.highestSurface(cave, 0, 0) == 130, "Highest roof must stay distinct from the lower floor");
|
||||
require(WoodlandGroveGeometry.naturalFootprint(cave, 0, 100, 0, 2), "A true 2x2 dark oak foot should fit");
|
||||
require(WoodlandGroveGeometry.treeRoom(cave, 0, 101, 0, 2, 6, 12), "Dark oak needs an actual free crown below the roof");
|
||||
require(!WoodlandGroveGeometry.treeRoom(cave, 0, 101, 0, 2, 6, 20), "Do not clip a canopy through its ceiling");
|
||||
WoodlandGroveGeometry.Sampler thin = (x,y,z) -> y == 100 ? 1 : -1;
|
||||
require(!WoodlandGroveGeometry.naturalFootprint(thin, 0, 100, 0, 2), "A floating one-block floor must not support a tree");
|
||||
WoodlandGroveGeometry.Sampler pierced = (x,y,z) -> x == 1 && z == 1 && y <= 100 ? -1 : cave.sample(x,y,z);
|
||||
require(!WoodlandGroveGeometry.naturalFootprint(pierced, 0, 100, 0, 2), "Every one of the four trunk supports must exist");
|
||||
require(WoodlandGroveGeometry.seed(42, 3, 4, 5, 9) == WoodlandGroveGeometry.seed(42, 3, 4, 5, 9), "Placement must replay");
|
||||
require(WoodlandGroveGeometry.seed(42, 3, 4, 5, 9) != WoodlandGroveGeometry.seed(43, 3, 4, 5, 9), "World seed must affect placement");
|
||||
System.out.println("WoodlandGroveSmoke: natural multi-block feet and real canopy clearance passed.");
|
||||
}
|
||||
private static void require(boolean condition, String message) { if (!condition) throw new AssertionError(message); }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package fr.koka.sanctuary.worldgen;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/** Regression: a higher hill must not replace ordinary oak/birch climate with exposed stone. */
|
||||
public final class WoodlandPaletteSmoke {
|
||||
public static void main(String[] args) {
|
||||
for (int y = 240; y < 384; y++) {
|
||||
require(WoodlandBiomePalette.select(y, 0.2F, 0.2F) == WoodlandBiomePalette.Kind.OAK_FOREST,
|
||||
"Raising a temperate forest must retain its oak cover");
|
||||
require(WoodlandBiomePalette.select(y, -0.45F, 0.1F) == WoodlandBiomePalette.Kind.BIRCH_FOREST,
|
||||
"A high birch woodland must not become a meadow or bare stone because of altitude");
|
||||
}
|
||||
require(WoodlandBiomePalette.select(144, 0.2F, 0.2F) == WoodlandBiomePalette.Kind.DARK_GROVE,
|
||||
"The corresponding sheltered lower layer must have a distinct humid woodland");
|
||||
require(WoodlandBiomePalette.select(144, -0.6F, 0.7F) == WoodlandBiomePalette.Kind.BAMBOO_GROVE,
|
||||
"A warm humid lower pocket must support the rare bamboo palette");
|
||||
require(WoodlandBiomePalette.select(80, 0.75F, -0.5F) == WoodlandBiomePalette.Kind.SULFUR_DEPTHS,
|
||||
"The deep geological pocket must remain reachable");
|
||||
for (int y = 144; y < 384; y++) require(
|
||||
WoodlandBiomePalette.select(y, 0.75F, -0.5F) != WoodlandBiomePalette.Kind.SULFUR_DEPTHS,
|
||||
"Sulfur pockets must not cover ordinary upper surfaces");
|
||||
for (int y = 144; y < 384; y += 8) require(
|
||||
WoodlandBiomePalette.select(y, 0.6F, 0.2F) == WoodlandBiomePalette.Kind.ROCKY_HEATH,
|
||||
"The strongest horizontal rock patches must remain recognizable across layers");
|
||||
EnumSet<WoodlandBiomePalette.Kind> reachable = EnumSet.noneOf(WoodlandBiomePalette.Kind.class);
|
||||
for (int y = 32; y < 384; y += 8) for (int variation = -10; variation <= 10; variation++) {
|
||||
for (int moisture = -10; moisture <= 10; moisture++) {
|
||||
reachable.add(WoodlandBiomePalette.select(y, variation / 10.0F, moisture / 10.0F));
|
||||
}
|
||||
}
|
||||
require(reachable.equals(EnumSet.allOf(WoodlandBiomePalette.Kind.class)),
|
||||
"All eight declared palettes must be reachable within the dimension");
|
||||
System.out.println("WoodlandPaletteSmoke: persistent upper forests, sheltered groves, bounded sulfur depths and horizontal rock patches passed.");
|
||||
}
|
||||
|
||||
private static void require(boolean condition, String message) {
|
||||
if (!condition) throw new AssertionError(message);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -51,7 +51,7 @@ Pour produire un fichier importable par un lanceur compatible Modrinth :
|
||||
|
||||
```sh
|
||||
cd build/packwiz # depuis la racine du dépôt
|
||||
packwiz modrinth export --output ../Sanctuary-0.1.0-alpha.6.mrpack
|
||||
packwiz modrinth export --output ../Sanctuary-0.1.0-alpha.7.mrpack
|
||||
```
|
||||
|
||||
L'export contient le JAR Sanctuary local et la référence vérifiée de Fabric API.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
name = "Sanctuary"
|
||||
author = "KOKA99CAB"
|
||||
version = "0.1.0-alpha.6"
|
||||
version = "0.1.0-alpha.7"
|
||||
pack-format = "packwiz:1.1.0"
|
||||
|
||||
[index]
|
||||
|
||||
Reference in New Issue
Block a user