Compare commits

...
Author SHA1 Message Date
koka 00d175cb98 Deliver beta.235 as a verified reversible Pause layout experiment
Build Sanctuary / build (push) Waiting to run
2026-10-06 14:21:31 +02:00
koka a7bdfe6998 Try parallel Pause groups before Atlas and a narrow stack beside the map 2026-10-06 14:16:40 +02:00
koka f9c2ce8835 Deliver beta.234 with verified Story catalogue and local pack
Build Sanctuary / build (push) Waiting to run
2026-10-06 04:50:30 +02:00
koka 3d56d7de7f Verify Story menus under Vulkan and document story authoring 2026-10-06 04:49:56 +02:00
koka f2ac23b4f4 Add Story catalogue with search and discovery filters 2026-10-06 04:46:02 +02:00
koka 9c096b2563 Deliver beta.233 with verified community forms and Vulkan layouts
Build Sanctuary / build (push) Canceled after 0s
2026-10-06 03:59:50 +02:00
koka bc27606b3e Simplify notices and place Gazette photos before the title 2026-10-06 03:57:17 +02:00
koka 8531bb3476 Group pause navigation consistently with and without the map 2026-10-06 03:57:17 +02:00
koka 8e9b8fbd62 Deliver beta.232 with verified solo gameplay and Vulkan client checks 2026-10-06 03:25:17 +02:00
koka 308c0dc2ff Center the locked Atlas pause menu between Gazette and Notice Board 2026-10-06 03:24:47 +02:00
koka 50aaa5c135 Exclude generated diamonds from initial island chest loot 2026-10-06 03:24:47 +02:00
koka cf5699cfe1 Continue held vein mining on the next visible group after server completion 2026-10-06 03:24:46 +02:00
koka d9979100a9 Align placement outlines with building reach from three to seven blocks 2026-10-06 03:24:46 +02:00
koka 5f3d110773 Allow the solo owner to choose a persistent world timezone 2026-10-06 03:24:33 +02:00
koka a2201cc422 beta.231: enrich pale understory and prepare nine-island lab
Build Sanctuary / build (push) Canceled after 0s
2026-10-05 23:08:05 +02:00
koka 42e42fea2a beta.230: populate lower pale terraces and mix yellow savanna rock 2026-10-05 22:45:45 +02:00
koka 55df522b1e beta.229: rebuild northeast wetland above sheltered pale groves 2026-10-05 22:24:29 +02:00
koka b77d71bd0d Lower pale wetlands and facet diagonal reefs for beta.228 2026-10-05 21:55:12 +02:00
koka 70a34df2d5 Refine diagonal shores and cave habitats for beta.227 2026-10-05 21:34:48 +02:00
koka 5fb1407705 beta.226: shape four distinct diagonal landscapes 2026-10-05 20:34:13 +02:00
koka e2b9ee7aaf feat(worldgen): add 1024 climate diagonals and island sugar cane in beta.225 2026-10-05 19:44:33 +02:00
koka 1388d8a443 docs: confirm all four islands in standard Sanctuary beta.224 2026-10-05 17:34:55 +02:00
koka 4554ea1882 fix(worldgen): ground giant trees and stripe the East crater in beta.224 2026-10-05 17:29:49 +02:00
koka 9063e16e7c feat(worldgen): add natural floating jungle volcano in beta.223 2026-10-05 17:11:17 +02:00
koka 2d656d9525 feat(building): add yellow rock stairs and slabs in beta.222 2026-10-05 16:50:38 +02:00
koka a3dd17c37a feat(worldgen): refine western cliffs and add yellow stone in beta.221 2026-10-05 16:34:55 +02:00
koka 58aa4c2ae1 feat(worldgen): sculpt a living western coast in beta.220 2026-10-05 16:09:03 +02:00
koka 988a6c8f51 feat(worldgen): lower western beaches and move palms in beta.219 2026-10-05 15:17:07 +02:00
koka 3adb08eaa6 feat(worldgen): reshape western ocean into an oasis in beta.218 2026-10-05 14:52:25 +02:00
koka f8456df256 feat(worldgen): add suspended western sea in beta.217 2026-10-05 14:15:02 +02:00
koka 0eb4517961 beta.216: forests, surface trails and trapped pyramid in the South 2026-10-05 08:37:08 +02:00
koka 03aab49996 Add raised regional relay monuments and enlarge the southern pyramid for beta.215 2026-10-05 07:50:14 +02:00
koka b82ab378f0 Add abandoned dark oak western village to South beta.214 2026-10-05 07:21:47 +02:00
koka da838b9e8e beta.213: bury the southern temple beneath a local terracotta pyramid 2026-10-05 06:33:30 +02:00
koka 3941bd4711 beta.212: expose radial Badlands and add a trapped desert complex 2026-10-05 06:11:04 +02:00
koka 7375046488 Rebuild southern badlands with shattered native noise for beta.211 2026-10-05 05:29:42 +02:00
koka 2ee53e1065 Refine southern canyon palettes and dry ecology for beta.210 2026-10-05 05:03:50 +02:00
koka efb1097b65 feat(worldgen): prototype multicoloured South canyons in beta.209 2026-10-05 04:26:51 +02:00
koka d021341d3e Sharpen northern ridges and add supported glacial benches for beta.208 2026-10-05 03:24:32 +02:00
koka bb10c24ada Add patchy northern snow, local crowns and spruce mansion for beta.207 2026-10-05 02:29:06 +02:00
koka 6f780547bb Shape thinner northern shelves and wet amethyst caves for beta.206 2026-10-05 01:32:41 +02:00
koka bf5df3885b Use unwarped native noise and continuous northern ecology for beta.205 2026-10-05 00:37:26 +02:00
koka 2463db72f7 Integrate Demeure and Sanctuary terrain with northern Peaks for beta.204 2026-10-05 00:07:08 +02:00
koka 454d9a5c08 Add fractured northern relief and giant taiga for beta.203
Build Sanctuary / build (push) Canceled after 0s
2026-10-04 13:13:17 +02:00
koka ba1b228e76 Refine northern ecology and snowy igloo placement for beta.202 2026-10-04 12:42:16 +02:00
koka 1d60a3eedc feat: compact northern glacier and use vanilla ice spikes in beta.201 2026-10-04 12:05:38 +02:00
koka 16d81d892f feat: deliver beta.200 North expansion and igloo village 2026-10-04 05:52:20 +02:00
koka 7497d9182d beta.199: connect runtime expansions and synchronize the stellar week 2026-10-01 21:38:44 +02:00
koka 6b97d57bde Fix seed-dependent central gallery creation in beta.198 2026-10-01 20:02:28 +02:00
koka 7c14696020 beta.197: repair island arrival, dungeon details and seed-dependent gallery creation 2026-10-01 19:37:37 +02:00
koka 39ff7e95d5 beta.196: share the current island lab in three sizes and profile loading 2026-10-01 18:40:01 +02:00
koka 918143aaa6 beta.195: hide legacy lab presets and open the seed zero visit 2026-10-01 18:02:21 +02:00
koka 9da3f7f13b beta.194: remove Friends from the title menu and pause terrain work 2026-10-01 01:42:49 +02:00
koka 7179b5d4cb beta.193: protect worldgen water and add native multiseed photo comparisons 2026-10-01 01:29:17 +02:00
koka 78f047d3dc beta.192: sculpt local summit crowns and rocky mountain faces 2026-09-30 22:34:43 +02:00
koka c7f32c9416 beta.191: restore pre-terrace relief and original surface geology 2026-09-30 21:47:10 +02:00
koka 97ea94e482 beta.190: restore organic relief, widen spillways and stock ruin chests 2026-09-30 21:05:30 +02:00
koka 51e7e2590e beta.189: fit refuges to terrain and finish shores, terraces and cave ruins 2026-09-30 20:31:06 +02:00
koka 658aaf8732 beta.188: add living lake beds, sulfur details and enchanted iron loot 2026-09-30 09:04:25 +02:00
koka c53b39e71c Integrate beta.187 natural sulfur caves, surface lakes and oriented anchors 2026-09-30 08:41:38 +02:00
koka f40382ad04 Build beta.186 ornamental rosettes and eight terrain-bound anchors 2026-09-30 08:09:11 +02:00
koka a067c7e66b Build beta.185 fine stem and integrated palace roof portal 2026-09-30 07:33:49 +02:00
koka 6cfa4c07bf Build beta.184 natural sky palace and fill retained terrain cavities 2026-09-30 03:46:00 +02:00
koka 1ca01a47b7 Confirm beta.183 solo entry and spectator visit 2026-09-30 03:12:37 +02:00
koka a46946bd4c Add beta.183 island discoveries and adaptive ISS atlas 2026-09-30 03:10:10 +02:00
koka 65e7127b1d Add beta.182 natural lower gallery and eight-axis glass rosette 2026-09-30 02:23:35 +02:00
841 changed files with 56896 additions and 694 deletions
+490 -1
View File
@@ -1,11 +1,500 @@
# Sanctuary
Les **quatre expansions validées sont disponibles dans Sanctuary normal** :
Nord glacial, Sud des canyons, Ouest océanique et Est volcanique.
Créer un monde **Sanctuary** en Petit, Moyen ou Grand, puis activer les ancres
correspondantes. Le module Sanctuary Test n’est pas requis.
[Intégration et vérification du pack beta.224](docs/four-islands-base224.md).
## beta.235 — Essai réversible du menu Pause
[Disposition adaptative](docs/pause-columns-beta235.md) : avant Atlas, Aventure
à gauche et Communauté à droite, avec Partie / Game juste dessous. Avec Atlas,
une colonne étroite à gauche, Communauté → Aventure → Game, carte au centre.
Bloc centré verticalement, libellés de navigation entiers et ordre clavier
adapté. Parcours Pause et Story Vulkan FR/EN GUI 2/3/4, `check build assemblePack`
et quatre GameTests ciblés réussis.
Le commit de disposition `a7bdfe6` peut être annulé indépendamment de la
livraison. [MRpack local beta.235](build/Sanctuary-beta.235.mrpack) vérifié,
sans publication ni mise à jour personnelle. Le rendu reste à apprécier.
## beta.234 — Story, recherche et filtres
[Premier menu Story](docs/story-beta234.md), sous Progression dans Aventure :
100 histoires inconnues et désactivées, recherche instantanée et filtre
Toutes/Découvertes/Inconnues, cadre de Discovery et retour à Pause. Saisie et
défilement conservés au redimensionnement ; trois boutons Aventure centrés
avec ou sans Atlas. [Guide](docs/story/README.md) et
[modèle Markdown](docs/story/TEMPLATE.md) pour les futurs récits personnels.
Textes et déblocages restent à intégrer. `check build assemblePack`, quatre
GameTests requis et parcours Vulkan FR/EN GUI 2/3/4 réussis.
[MRpack local beta.234](build/Sanctuary-beta.234.mrpack) vérifié ; aucune
publication ni mise à jour d'installation personnelle.
## beta.233 — Navigation centrée et rédaction simplifiée
[Ajustements du menu et des formulaires](docs/pause-community-beta233.md) : même
ordre avec et sans carte, Communauté (Habitant/Faction/Battle) en haut,
Aventure (Discovery/Progression) au centre et Partie (options/sortie) en bas,
sans barre sous Communauté. Notice Board sans choix de catégorie, notices
uniformes, demandes et récompenses sous le texte, puis Publish. Photo et
Choose a screenshot de la Gazette avant le titre. Brouillons et anciennes
catégories conservés ; parcours de publication et essais Vulkan FR/EN réussis.
`check build assemblePack` avec la suite menus : quatre GameTests requis et
contrôles communautaires réussis. [MRpack local beta.233](build/Sanctuary-beta.233.mrpack)
vérifié ; aucune installation personnelle ni mise à jour du canal.
## beta.232 — Session solo et progression
[Réglages et correctifs](docs/solo-gameplay-beta232.md) : fuseau persistant via
`/sanctuary time timezone Europe/Paris` ou `auto`, disponible au propriétaire
solo sans commandes opérateur. Portée de Construction de 3 à 7 blocs, contour
et pose cohérents ; vein mining maintenu enchaînant sur le bloc regardé.
Aucun diamant généré par les coffres de l'île initiale ; inventaires déjà
remplis et terrain conservés. Avant Atlas : Gazette à gauche, huit boutons
centrés, Notice Board à droite, aucune World Map. Build, 26 GameTests requis
et essais client Vulkan FR/EN réussis.
[MRpack local beta.232](build/Sanctuary-beta.232.mrpack) vérifié ; aucune
installation personnelle ni mise à jour du canal.
## beta.231 — Sous-bois pâles et archipel complet
[Correctif et visite](docs/diagonal-understory-beta231.md) : herbes, fleurs,
tapis de mousse et mousse suspendue dans les parties basses du jardin pâle.
Reliefs et autres habitats validés conservés. Cinq GameTests et build complet
réussis ; huit expansions activées autour d’une principale de 1024, sur 0.
[MRpack normal beta.231](build/Sanctuary-beta.231.mrpack) vérifié.
Le joueur choisit une visite immédiate ; prégénération intégrale interrompue
proprement, chargement restant pendant l’exploration. Labo Vulkan 32 chunks
ouvert au centre de l’île principale ; rendu à apprécier.
## beta.230 — Terrasses pâles et roche jaune
[Correctif des diagonales](docs/diagonal-lower-groves-beta230.md) : chênes pâles
sur les sols bas, abrités ou à ciel ouvert, dripstone dans le dessous du NE.
Savane mêlant roche jaune et pierre normale, minerais conservés. Reliefs,
mangroves et plaines validés conservés. Nouveaux profils uniquement.
Neuf GameTests, build complet et essais natifs 0/42 réussis.
[MRpack normal beta.230](build/Sanctuary-beta.230.mrpack) vérifié ; nouveau
labo Vulkan 32 chunks ouvert sur 0. Rendu à apprécier.
## beta.229 — Marais étagé et cavités sèches
[Refonte du Nord-Est](docs/diagonal-wetland-beta229.md) : relief de la savane
amincie, chênes pâles sous les surplombs, marais et lucioles au-dessus. Eau
uniquement dans des cuvettes naturelles fermées. Cavités soufre/dripstone au
Sud-Ouest, sans lush caves ; mangroves SE et plaines NO conservées. Nouveaux
profils uniquement. Huit GameTests, build complet et essais natifs 0/42
réussis. [MRpack normal beta.229](build/Sanctuary-beta.229.mrpack) vérifié ;
nouvelle visite Vulkan 32 chunks ouverte sur 0. Rendu à apprécier.
## beta.228 — Jardin pâle abaissé et fractures anguleuses
[Finition des diagonales](docs/diagonal-shaping-beta228.md) : jardin pâle
nettement abaissé, lacs remis en évidence, formes plus anguleuses dans les
mangroves et sur les bordures des plaines. Centre NO, cavités SE et savane SO
conservés. Nouveaux profils uniquement. Sept GameTests, build complet et essais
natifs sur 0/42 réussis. [MRpack normal beta.228](build/Sanctuary-beta.228.mrpack)
vérifié ; visite Vulkan 32 chunks ouverte sur la graine 0. Rendu à apprécier.
## beta.227 — Berges, dessous et cavités des diagonales
[Réglages après exploration](docs/diagonal-caves-beta227.md) : jardin pâle plus
accidenté avec berges progressives et pourtour fracturé ; dessous désert/savane
aminci en gardant la surface ; grandes régions souterraines de lush caves et
de dripstone caves sous les mangroves ; érosion étendue vers l’intérieur au
Nord-Ouest, avec un centre de plaines conservé. Profils neufs uniquement.
Six GameTests, build complet et activations/reprise sur 0/42 réussis.
[MRpack normal beta.227](build/Sanctuary-beta.227.mrpack) vérifié ; nouvelle visite
Vulkan 32 chunks ouverte sur la graine 0, quatre diagonales prêtes. Rendu à apprécier.
## beta.226 — Quatre reliefs diagonaux distincts
[Refonte des silhouettes](docs/diagonal-relief-beta226.md) : grandes plaines
centrales et bords rongés au Nord-Ouest ; bassins conservés, marais peu profonds
et hauts reliefs émergés au Nord-Est ; désert/savane sur terrain flottant 3D au
Sud-Ouest ; récifs verticaux à mangrove dominante au Sud-Est, avec boue, argile
et calcite. Diamètre 1024 et axes climatiques conservés. Nouveaux mondes
uniquement ; les profils précédents restent disponibles pour leurs sauvegardes.
Six GameTests, build complet et activations/reprise sur 0/42 réussis.
[MRpack normal beta.226](build/Sanctuary-beta.226.mrpack) vérifié ; visite Vulkan
32 chunks ouverte sur la graine 0, quatre diagonales prêtes. Rendu à apprécier.
## beta.225 — Diagonales climatiques et cannes à sucre
[Première génération des quatre diagonales](docs/diagonal-islands-beta225.md),
chacune de **1024 blocs** : Nord-Est humide avec jardin pâle et marais,
Nord-Ouest frais avec meadow et taïga, Sud-Est tropical avec mangroves et jungles,
Sud-Ouest sec avec désert et savane. Cannes à sucre sur les berges existantes
de Sanctuary Island. Nouveaux profils Petit/Moyen/Grand uniquement ;
les quatre cardinales validées et les anciens profils sont conservés.
Six GameTests, build et activations/reprise sur les graines 42/0 réussis.
Le [MRpack normal](build/Sanctuary-beta.225.mrpack) contient ces ajouts sans Test ;
le rendu reste à apprécier en jeu.
## beta.224 — Stries du cratère Est
[Finition du volcan](docs/east-crater-beta224.md) : relief 223 conservé, lignes
concentriques et hachures verticales, obsidienne étendue et fissures de magma.
Plantation des arbres géants limitée au sol naturel. Sept GameTests ciblés,
build et essais natifs 42/0 réussis ; [MRpack normal](build/Sanctuary-beta.224.mrpack)
vérifié. Nouvelle visite Vulkan 32 chunks ouverte ; rendu à apprécier en jeu.
## beta.223 — Volcan flottant de l’Est
[Premier volcan et jungles](docs/east-volcano-beta223.md) : cône asymétrique,
cratère de lave fermé, ravines ramifiées, jungles ouvertes/denses et bambou,
grands arbres natifs, pandas et temple de jungle avec pièges et butin.
Expansion Est 1024, nouveaux profils uniquement. Build, sept GameTests ciblés
et essais natifs 42/0 réussis ; [MRpack normal](build/Sanctuary-beta.223.mrpack)
vérifié. Visite Vulkan 32 chunks ouverte ; rendu à apprécier en jeu.
Nord, Sud, Ouest et île principale conservés.
## beta.222 — Roche jaune et déclinaisons
[Famille de construction](docs/yellow-rock-beta222.md) : nouveau nom Roche jaune,
escaliers et dalles, recettes natives à l’établi et au tailleur de pierre.
Bloc dans Naturel, famille dans Construction à côté de Stone. Génération 221
conservée ; cinq GameTests et 87 états de modèles sous Vulkan vérifiés.
[MRpack normal](build/Sanctuary-beta.222.mrpack) prêt.
## beta.221 — Pierre jaune de l’Ouest
[Finition des parois](docs/west-yellow-stone-beta221.md) : arbres écorcés et
passe de ravins retirés, relief 3D conservé avec un Voronoi discret, sols plus
cohérents. Nouvelle pierre jaune mineable, juste après Stone dans Naturel et
Construction. Build, six GameTests ciblés et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.221.mrpack) vérifié. Nouveaux profils uniquement.
## beta.220 — Couronne vivante de l’Ouest
[Berges et reliefs](docs/west-living-rim-beta220.md) : plage libre de 12–15 blocs,
palmiers en retrait, bosquets fleuris, cactus, bois mort et herbes sèches.
Reliefs, ravins et cavités 3D sur le pourtour ; océan, monument et épaves
conservés. Build, cinq GameTests ciblés et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.220.mrpack) vérifié. Nouveaux profils uniquement.
## beta.219 — Plages basses de l’Ouest
[Finition des berges](docs/west-beaches-beta219.md) : sable au niveau de l’eau
sur environ quatre blocs, montée douce et palmiers denses sur la rive intérieure.
Soufre et cinabre retirés de cette couronne. Océan, temple et épaves 218 conservés.
Six GameTests ciblés et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.219.mrpack) vérifié. Nouveaux profils uniquement.
## beta.218 — Falaises sous-marines et oasis de l’Ouest
[Nouvelle cuve océanique](docs/west-oasis-beta218.md) : plateau sous-marin,
fracture centrale avec monument, plages de grès et palmiers, soufre et cinabre,
quatre épaves natives. Racines et calcite retirées de ce nouvel Ouest.
Île principale, Nord, Sud et anciens profils conservés. Sept GameTests et
essais natifs 42/0 réussis ; [MRpack normal](build/Sanctuary-beta.218.mrpack)
vérifié. Nouvelle visite Vulkan 32 chunks ; rendu à apprécier en jeu.
## beta.217 — Mer suspendue de l’Ouest
[Premier océan](docs/west-ocean-beta217.md) : mer de 1024 blocs, cuve rocheuse
fermée, racines ramifiées et bords minéraux déformés par bruit 3D. Monument
océanique obligatoire, coraux et relais surélevé. Nord, Sud et île principale
conservés. Build, cinq GameTests ciblés et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.217.mrpack) vérifié. Nouvelle visite
Vulkan à 32 chunks ouverte ; rendu à apprécier en jeu.
## beta.216 — Forêts et pièges du Sud
[Dernière passe du Sud](docs/south-forest-beta216.md) : forêts denses de chênes
sur la terre, sentiers de surface, pyramide sans torches et plaques piégées
dans les salles et couloirs. Les 14 teintes et le relief sont conservés.
Huit GameTests ciblés, assemblages et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.216.mrpack) vérifié. Nouvelle visite
Vulkan 32 chunks ouverte. La graine 0 reste sans pyramide faute de site enterré.
## beta.215 — Relais régionaux
[Monuments du Nord et du Sud](docs/regional-relays-beta215.md) : relais
surélevés, socles massifs et matériaux locaux ; rosace entièrement colorée.
Village Far West retiré des nouveaux profils, pyramide extérieure agrandie
à 31 × 31, intérieur conservé. Contrôles purs, dix GameTests ciblés et
essais natifs Sud 42 / Nord 0 réussis. [MRpack normal](build/Sanctuary-beta.215.mrpack)
exporté localement ; nouvelle visite Vulkan à 32 chunks. Rendu à apprécier en jeu.
## beta.214 — Village Far West abandonné
[Village décoratif du Sud](docs/south-western-beta214.md) : sept ou huit maisons
en chêne noir, rue principale, porches, façades ornées, lanternes et traces
d’abandon. Implantation et dimensions varient avec la graine, sur les surfaces
du canyon. Terrain et pyramide 213 conservés ; nouveaux profils uniquement.
Contrôles purs, neuf GameTests ciblés et génération/reprise sur 42/0 réussis.
[MRpack normal](build/Sanctuary-beta.214.mrpack) exporté localement ; nouvelle
visite Vulkan à 32 chunks ouverte. Le rendu reste à apprécier en jeu.
## beta.213 — Pyramide et chambres enterrées
[Correction ciblée du Sud](docs/south-buried-beta213.md) : relief et couleurs
212 conservés, sables de surface et acacias custom retirés. Pyramide camouflée
en terracotta locale, descente vers dix petites salles, couloirs et pièges.
Nouveaux profils uniquement. Contrôles purs, 12 GameTests ciblés et essais natifs
42/0 réussis ; [MRpack normal](build/Sanctuary-beta.213.mrpack) exporté localement.
Rendu à apprécier dans la nouvelle visite Vulkan à 32 chunks.
## beta.212 — Couronnes colorées et complexe du désert
[Évolution du Sud](docs/south-rings-beta212.md) : couleurs radiales visibles,
reliefs de mesa localisés, désert clair, arbres secs et petits arbres feuillus.
Grand complexe de grès avec salles, caches et pièges TNT.
Nouveaux profils uniquement ; Nord et île principale conservés.
Contrôles purs, 12 GameTests ciblés et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.212.mrpack) exporté localement.
Rendu à apprécier dans la nouvelle visite Vulkan à 32 chunks.
## beta.211 — Sud fracturé et cœur coloré
[Refonte des Badlands](docs/south-shattered-beta211.md) : retour au bruit 3D
natif flottant, fissures sans Voronoi, dessous aminci, bandes vanilla dehors
et huit teintes dans le cœur exposé. Sud 1024, nouveaux profils uniquement.
Contrôles purs, 10 GameTests ciblés et essais natifs 42/0 passés ;
[MRpack normal](build/Sanctuary-beta.211.mrpack) exporté localement.
Le rendu reste à apprécier dans la nouvelle visite Vulkan à 32 chunks.
## beta.210 — teintes et végétation des canyons
[Habillage du Sud](docs/south-palette-beta210.md) : quatre familles terreuses par
massif, strates irrégulières discrètes, sol de vallée continu et végétation sèche
aussi sur les mesas. Relief 209 et Nord 208 conservés. Nouveaux profils uniquement.
Build, 11 tests ciblés et essais natifs 42/0 réussis ;
[MRpack normal](build/Sanctuary-beta.210.mrpack) exporté localement.
Le rendu reste à apprécier dans la nouvelle visite Vulkan à 32 chunks.
## beta.209 — premier Sud multicolore
[Prototype des Badlands](docs/south-badlands-beta209.md) : expansion Sud de 1024 blocs,
réseau de canyons par Voronoi inversé, mesas et strates plissées avec les seize
terracottas. Sables assortis sur les surfaces portantes ; Nord 208 conservé.
Nouveaux profils uniquement. Compilation, contrôles ciblés et essais natifs
sur 42 et 0 passés ; [MRpack normal](build/Sanctuary-beta.209.mrpack) exporté
localement. Le rendu est à apprécier dans la nouvelle visite.
## beta.208 — crêtes et replats glacés du Nord
[Dernière passe du Nord](docs/north-ridges-beta208.md) : sommets anguleux,
entailles et replats localisés avec poches et aiguilles de glace. Taïga,
améthyste, igloos et manoir en épicéa conservés. Nouveaux profils uniquement ;
compilation, tests ciblés et essais natifs sur 42 et 0 passés.
[MRpack normal](build/Sanctuary-beta.208.mrpack) exporté localement.
## beta.207 — paysages et manoir du Nord
[Nouvelle passe du Nord](docs/north-landscape-beta207.md) : neige irrégulière
dans une partie des taïgas, reliefs Voronoi localisés sur les hauts plateaux et
manoir procédural en épicéa. Diamètre, dessous aminci et failles d’améthyste
conservés. Profils neufs uniquement ; contrôles natifs sur les graines 42 et 0
passés. [MRpack normal](build/Sanctuary-beta.207.mrpack) exporté localement.
## beta.206 — cavités froides du Nord
Le [nouveau dessous du Nord](docs/north-cavities-beta206.md) conserve le paysage
de surface de la 205 et amincit sa masse rocheuse avec des épaisseurs variables.
Les cavités accueillent glace, eau dans les creux fermés et failles ouvertes
d’améthyste bordées de calcite et de basalte. Nouveaux mondes uniquement ;
la répartition géographique diorite/granit reste à décider.
Contrôles natifs sur les graines 42 et 0 passés ;
[MRpack normal](build/Sanctuary-beta.206.mrpack) exporté localement.
## beta.205 — Nord en bruit 3D natif
Le [nouveau profil nordique](docs/north-noise-beta205.md) retire l'étirement Peaks
et ses montagnes ajoutées. L'enveloppe grandit autour du bruit natif, puis la
taïga et la glace habillent ses surfaces. La lecture des hauteurs est interpolée
entre les points de mesure pour éviter les carrés de palette. Contrôles et
génération/reprise sur les graines 42 et 0 validés ; rendu à confirmer en visite.
[MRpack normal](build/Sanctuary-beta.205.mrpack) exporté localement.
## beta.204 — Sanctuary autonome et Nord Peaks
Le [chantier d’intégration](docs/base-peaks-beta204.md) transfère Demeure et
le terrain validé dans le mod principal. Sanctuary normal propose l’île récente
en Small, Medium ou Large ; le module Test reste facultatif pour les outils de
laboratoire. Le nouveau Nord reprend Peaks avec sa taïga géante et ses glaces.
Compilation, contrôles ciblés, création des trois tailles sans Test et éditeur
Vulkan FR/EN validés. [MRpack normal](build/Sanctuary-beta.204.mrpack) exporté
localement ; aucun canal public mis à jour. Nouveaux mondes uniquement.
## beta.203 — fractures et taïga géante au Nord
[Dernière passe du Nord](docs/north-fracture-beta203.md) : variations de relief
et ouvertures par bruit 3D, lisières de podzol irrégulières, épicéas pouvant
atteindre 64 blocs. La neige ajoutée après végétation est retirée ; les sommets
mêlent roche, neige et plusieurs glaces. Bassins protégés, cinq igloos conservés,
aucun nouveau village. Profils neufs seulement, Nord 1024.
## beta.202 — taïga et neige étagée au Nord
[Écologie nordique](docs/north-ecology-beta202.md) : relief et lacs 201 conservés,
vallées ouvertes et taïga sur herbe/podzol, grands épicéas et pics de glace natifs.
La neige varie avec l'altitude et le climat ; la glace des grottes reste derrière
une enveloppe rocheuse. Le village cherche une plaine entièrement enneigée.
Profils neufs uniquement, expansion de 1024 blocs.
## beta.201 — Nord compact et pics de glace vanilla
[Glacier nordique](docs/north-glacier-beta201.md) : diamètre ramené à 1024,
glace visible, deux lacs, bosquets d'épicéas et pics natifs `ice_spike` / `ice_patch`.
Le village de cinq igloos et son laboratoire sont conservés et rapprochés du lac.
Profils neufs uniquement ; les paysages froids des diagonales restent à concevoir.
## beta.200 — premier Nord glacial
[Expansion nordique](docs/north-expansion-beta200.md) : territoire de 2048 blocs,
crêtes enneigées, taïga, cavernes de glace, lacs gelés et village de cinq igloos,
dont un laboratoire souterrain. Placement dans la direction de l’ancre ; arrivée
et relais préparés, puis génération pendant l’exploration. Nouveaux mondes uniquement.
Export local : [MRpack de test](build/Sanctuary-Test-beta.200.mrpack).
Compilation, contrôles ciblés et activation/reprise du Nord vérifiés ; la suite
historique complète reste non validée, avec le détail dans le ticket.
## beta.199 — relais d’expansion en cours de partie
[Affinage du moteur existant](docs/runtime-expansions-beta199.md) : recherche
automatique proche sur 360°, régions minces, relais de continuation, reprise
après fermeture et annonce SGA à la fin. Nouveaux mondes de laboratoire
Small/Medium/Large ; étoiles synchronisées sur sept journées Minecraft.
## beta.198 — correction du plantage de création Large
[Admission de la galerie centrale](docs/gallery-generation-beta198.md) :
correction du défaut reproduit avec la graine Windows fournie, en conservant
le portail au centre et les anciens profils. Nouveaux mondes uniquement.
## beta.197 — arrivée et détails du laboratoire
[Corrections du laboratoire](docs/worldgen-fixes-beta197.md) : départ sur
l’île, cascades ouvertes vers l’extérieur, sol minier sans diagonales répétées
et toit de cabane continu. Nouveaux profils Small/Medium/Large ; enquête séparée
sur l’arrêt signalé chez un ami à la création Large.
## beta.196 — laboratoire à partager
[Pack de test Small, Medium et Large](docs/shared-lab-beta196.md) : une entrée
Sanctuary, taille personnalisable, dernier terrain du labo et atlas adapté.
Diagnostic du chargement et enregistrement JFR optionnel ; anciens mondes conservés.
## beta.195 — choix de génération simplifiés
[Sanctuary et les types vanilla](docs/worldgen-options-beta195.md) restent dans
la création de monde ; les variantes de labo sont masquées, leurs sauvegardes
restent lisibles. Nouvelle visite demandée sur le profil beta.193, graine 0,
avec le menu principal sans Amis. Le terrain est conservé pour cette comparaison.
## beta.194 — menu principal sans Amis
[Reprise des interfaces](docs/main-menu-beta194.md) : Solo et Multijoueur sont suivis
directement d’Options et Quitter, sans bouton Amis ni ligne vide. Le
[fil rouge](docs/storyquest-fil-rouge.md) reprend les interfaces et le Storyquest ;
les retouches de génération et les séries de captures sont suspendues.
## beta.193 — raccordements et comparaison visuelle
[Laboratoire sur plusieurs graines](docs/worldgen-continuity-beta193.md) : réservations
communes pour les bassins, ancres aériennes posées sur le terrain réel et
entailles locales du massif. Le nouveau profil `coherent` ajoute des contrôles
de collision entre aménagements et des visites photo Vulkan reproductibles.
Les anciens profils et sauvegardes restent séparés.
## beta.192 — couronnes et faces du massif
[Variante de relief érodé](docs/eroded-massif-beta192.md) : sommets localement
plus plats, faces rocheuses plus raides et entailles entre les reliefs.
Profil neuf `eroded`, graine 42 ; couverture végétale selon la pente réelle.
Les cavités profondes et les aménagements existants restent conservés.
## beta.191 — relief d’avant les plateaux
[Retour à la base beta.188](docs/restore-relief-beta191.md) : relief et géologie
antérieurs aux plateaux, passes de roche 189/190 retirées. Les corrections
indépendantes des berges, ancres, ruines et du portail restent présentes.
Profil neuf `original`, graine 42 ; génération, réouverture, 265 GameTests et
assemblages validés.
## beta.190 — retour au relief naturel
[Affinage de Sanctuary Island](docs/natural-refinement-beta190.md) : fin des
terrasses systématiques, épaules locales et affleurements sans cases de quatre
blocs. Déversoir proche de cinq blocs de large, coffres de fer enchanté dans les
quatre ruines. Profil `refined`, nouveau solo graine 42, vue 32 chunks.
Les reliefs très étagés passent dans la réserve des expansions futures.
## beta.189 — berges, reliefs et portail inférieur
[Finition de la génération](docs/terrain-finish-beta189.md) : refuges de surface
adaptés à la roche, sédiments selon profondeur et pente, berges sableuses,
plantations d’arbres protégées, reliefs étagés et affleurements. Portail inférieur
éclairé, cascade locale et quatre ruines sans excavation. Profil `finish`, nouvelle
sauvegarde, graine 42. 265 GameTests, génération, réouverture et assemblages réussis.
## beta.188 — fonds d’étangs et soufre vivant
[Laboratoire de finition](docs/living-details-beta188.md) : refuges adaptés
au milieu et à leur couleur, fonds mêlant argile, boue, sable et gravier,
végétation aquatique, pics et geysers natifs. Wagonnets avec une ou deux
pièces en fer enchanté. Profil `details`, monde neuf, graine 42.
265 GameTests, contrôles natifs et assemblages réussis ; solo Vulkan ouvert
à 32 chunks. Les anciennes sauvegardes restent inchangées.
## beta.187 — cavités de soufre et bassins de surface
[Nouveau laboratoire](docs/natural-caves-beta187.md) : soufre intégré aux
cavités existantes, trois bassins ouverts au ciel et huit ancres orientées
vers leur expansion, avec approche depuis le centre. Profil `natural`,
graine 42, nouvelle sauvegarde. Génération et réouverture vérifiées,
265 GameTests et assemblages réussis ; solo Vulkan ouvert à 32 chunks.
## beta.186 — rosaces et huit refuges d'ancres
[Nouveau laboratoire](docs/hidden-anchors-beta186.md) : balcon supérieur sans
barrières, liserés incrustés dans les deux dômes et huit ancres adaptées au terrain
de leur secteur. Dépôts distincts reliés aux gemmes du Bugrock. Profil `anchors`,
graine 42, nouvelle sauvegarde. Génération et réouverture vérifiées, 265 GameTests
et assemblages réussis ; solo Vulkan ouvert à 32 chunks.
## beta.185 — tige fine et portail de toiture
[Variante de laboratoire](docs/fine-stem-beta185.md) : ligne de calcite d’un bloc,
sans escalier ni paliers, fleur conservée, portail horizontal incrusté au sommet
et jour fermé sous les vitres du palais. Profil `stem`, monde neuf, graine 42.
265 GameTests, contrôles natifs et assemblages réussis ; solo Vulkan ouvert
à 32 chunks, départ dans le palais supérieur.
## beta.184 — ascension naturelle
[Nouveau laboratoire](docs/natural-ascent-beta184.md) : rosace et Bugrock à Y=640,
tige parcourable, palais vitré vers Y=1280 avec atlas au sol et portail horizontal.
La couronne se découvre en montant. Les bassins supérieurs dessinés sont remplacés
par le remplissage de creux existants. Profil `ascent`, nouveau monde uniquement.
265 GameTests, contrôles natifs et assemblages réussis ; solo Vulkan ouvert à
32 chunks, départ sur la rosace.
## beta.183 — lieux et ressources de l’île
[Nouveau laboratoire](docs/island-discovery-beta183.md) : portail horizontal,
secteurs de gemmes, soufre repérable, bassin supérieur, ISS et rosace aux huit
couleurs du Bugrock. ISS avec cartes horizontales, salle et mosaïque adaptées
au rayon du terrain. Profil `discovery`, monde neuf ; contrôles natifs,
265 GameTests et assemblages réussis. Solo préparé à 32 chunks.
## beta.182 — galerie inférieure et rosace
[Nouvelle scène de laboratoire](docs/origin-gallery-beta182.md) : galerie
naturelle sous le centre, trois salles à plusieurs niveaux, emplacement
d’obsidienne ; cloche vitrée au-dessus du Bug Rock et huit axes dégagés.
Nouveau profil `gallery`, monde neuf, contrôles natifs, 265 GameTests et
assemblages réussis. Solo à 32 chunks visité par le créateur, qui valide sa palette et sa rosace.
## beta.181 — origine à Y=320
[Premier repère central](docs/origin-landmark-beta181.md) : petite rose des vents
ouverte sur un fragment rocheux, Bug Rock en (0,320,0), lumineux et monochrome.
Nouveau profil de labo `origin`, fondé sur l’île beta.180 ; contrôle natif réussi
et solo Vulkan ouvert à 32 chunks. Suite générale de validation en cours.
et solo Vulkan ouvert à 32 chunks. Suite générale et assemblages réussis.
Les salles d’ancres, secteurs de gemmes, soufre, portail et ISS sont cadrés
comme suites à construire.
+2 -2
View File
@@ -52,11 +52,11 @@ Les resource packs, shaders et mods communautaires envisagés dans la vision
ne sont pas inclus automatiquement. Chaque ajout aura une version, une source,
un hash et les crédits de sa distribution.
Demeure est embarqué comme mod autonome, sous GPL-3.0-or-later. Son modèle
Demeure est intégré au code de Sanctuary depuis beta.204, sous GPL-3.0-or-later. Son modèle
provient des sources de KOKA99CAB dans `Structures/demeure`, référencées par
l’inventaire 26.2, et a été adapté à Minecraft 26.3-pre-2. Voir
`mods/demeure/PROVENANCE.md` pour les empreintes et les différences du port.
Le JAR Demeure contient sa licence et ce document de provenance.
Le JAR Sanctuary conserve sa licence GPL et `licenses/Demeure-PROVENANCE.md`.
## Inventaire beta.010
+2 -2
View File
@@ -3,8 +3,8 @@ plugins {
id 'net.fabricmc.fabric-loom' version "${loom_version}" apply false
}
tasks.named('build') { dependsOn(':sanctuary:build', ':demeure:build', ':jei:build', ':sanctuary-test:build') }
tasks.named('check') { dependsOn(':sanctuary:check', ':demeure:check', ':jei:check', ':sanctuary-test:check', 'verifyPack') }
tasks.named('build') { dependsOn(':sanctuary:build', ':jei:build', ':sanctuary-test:build') }
tasks.named('check') { dependsOn(':sanctuary:check', ':jei:check', ':sanctuary-test:check', 'verifyPack') }
tasks.register('verifyPack', Exec) {
group = 'verification'
+44
View File
@@ -1,5 +1,49 @@
# Backlog Sanctuary
## PAUSE-235 — groupes côte à côte avant Atlas — essai livré localement
Branche `codex/pause-columns-beta235`, base beta.234. Avant Atlas : Aventure à
gauche, Communauté à droite et Game juste dessous, bloc centré. Avec Atlas :
une colonne étroite à gauche dans l'ordre Communauté → Aventure → Game,
carte centrale et fils à droite. [Contrat et vérifications](pause-columns-beta235.md),
parcours Vulkan Pause et Story FR/EN GUI 2/3/4, build, quatre GameTests ciblés
et MRpack local vérifiés ; rendu à apprécier.
Commit de disposition `a7bdfe6` séparé des métadonnées pour permettre son retour.
## STORY-234 — recueil personnel avec recherche — livré localement
Branche `codex/story-beta234`, base beta.233. Story sous Progression dans
Aventure ; 100 histoires inconnues, barre de recherche et filtre de découverte.
Cadre commun avec Discovery, état de recherche et défilement conservés au
redimensionnement, accès avant et après Atlas. [Résultat et vérifications](story-beta234.md) :
build, quatre GameTests requis et parcours Vulkan FR/EN GUI 2/3/4 réussis.
[Modèle Markdown](story/TEMPLATE.md) pour les textes de l'auteur.
Les récits et leurs conditions de découverte restent des tickets suivants ;
aucun moteur de quête, format persistant ou déploiement ajouté.
## WG-RESTORE-191 — annuler les plateaux et leurs affleurements
La visite beta.190 ne valide pas le relief corrigé. [Retour exact à la base
beta.188](restore-relief-beta191.md), pour la densité et la géologie naturelle.
Conserver les aménagements indépendants ; réserver les futures singularités
de relief à quelques endroits. Nouveau profil `original` ; 134 480 densités
comparées à l’identique, génération/réouverture et 265 GameTests réussis.
## WG-NATURE-190 — revenir au relief organique
Retour beta.189 : [contrat beta.190](natural-refinement-beta190.md). Relief local
adouci, sortie d’étang large et proche, coffres de fer enchanté dans les ruines.
Profil neuf de laboratoire ; génération, réouverture, 265 GameTests et assemblages
validés. Solo Vulkan ouvert à 32 chunks.
## Réserve d’expansion — grandes surfaces ciselées
Conserver la variante de terrasses beta.189 comme piste pour une autre expansion :
grands plateaux, falaises étagées, profondeurs et verticalité variables selon
l’identité de l’île. Ne plus appliquer ces niveaux partout sur Sanctuary Island.
Aucune expansion activée. Le portail à remplissage avec ressource renouvelable
reste à concevoir ; les perles d’Ender sont une possibilité, pas une décision.
## WG-ECO-177 — écologie liée au relief
Branche `codex/relief-ecology-beta177`. Nouveau solo à 32 chunks demandé
+103
View File
@@ -0,0 +1,103 @@
# UNI-WG-204 — Sanctuary autonome et Nord Peaks
Branche `codex/sanctuary-base-peaks-beta204`, depuis beta.203 (`454d9a5`).
Demande : absorber Demeure dans Sanctuary, rendre le terrain validé du laboratoire
accessible avec le mod normal seul, puis remplacer la nappe nordique par le
générateur Peaks existant en conservant taïga géante, glaces et igloos.
## Contrat
- Demeure interne : même chemin `data/demeure/footprints-v1.json`, schéma 1,
mêmes règles serveur et attribution. Aucun transfert de données.
- Nouveau preset public Sanctuary, trois tailles ; types vanilla conservés.
Introduction normale conservée ; diagnostics et raccourcis de labo facultatifs.
- Codecs et ressources historiques `sanctuary:*` et `sanctuary_test:*` conservés.
Le transfert de module ne renomme pas ces identifiants.
- Nouveau profil 204 uniquement pour le Nord Peaks, diamètre 1024. L'île de
départ reprend les paramètres 203 ; aucun terrain déjà créé régénéré.
- Essais sur mondes de développement neufs et copies de développement seulement,
graines 0, 42 et 4736390610738281858 ; publication/installation non demandée.
## Réalisation
### Mod normal
Demeure n'est plus un JAR Fabric imbriqué : ses quatre classes, son mixin de
placement, ses tests et son attribution sont intégrés à Sanctuary. Le service
s'enregistre une seule fois depuis l'initialisation principale. Un ancien JAR
Demeure séparé est refusé pour éviter deux installations des mêmes hooks.
Le terrain validé restait dans `sanctuary-test` ; le preset public du mod normal
ne pointait donc pas vers ce terrain. Le runtime de l'île, ses ressources,
ses mixins et son écran de taille sont désormais dans Sanctuary : biomes,
grottes, minerais, bassins, mines, ruines, ancres, rosace, station et expansions.
Les variantes historiques restent enregistrées pour lire leurs identifiants,
mais une seule entrée Sanctuary apparaît dans le menu, à côté des types vanilla.
Small/Medium/Large sélectionnent les nouveaux paramètres `sanctuary:island204_*`.
Le module Test conserve uniquement ses outils : diagnostics, visites guidées de
développement, monde plat, commandes et raccourcis d'essai. Il ne fournit plus
de mixin ou de ressource indispensable au monde normal. Le nom du package Java
`fr.koka.sanctuarytest` et les anciennes clés `sanctuary_test:*` restent inchangés
dans le runtime déplacé afin de limiter la portée du transfert.
### Nord
Pour les nouveaux profils 204, le Nord 1024 utilise directement la densité Peaks
du moteur d'expansion, avec son épaisseur et son amplitude verticales normales.
La coque de plateaux `NorthShape203` n'intervient plus. L'écologie s'appuie sur
des colonnes mesurées dans cette densité, mises en cache sur une grille de huit
blocs : vallées, taïga, vieux épicéas, roche, neige, pics et glaciers dépendent
du relief. Les épicéas géants 203 et les formations de glace vanilla sont repris.
La glace des cavernes reste conditionnée à une couverture rocheuse suffisante.
Les cinq igloos cherchent des épaules enneigées suffisamment soutenues, sans
aplatir toute la montagne ; un seul possède le laboratoire de guérison. L'arrivée
et le relais évitent les bâtiments. Les deux bassins imposés dans les anciens
profils nordiques ne sont pas transposés : ils reformaient des plateformes dans
le nouveau relief. Les autres directions et les profils 200–203 ne changent pas.
## Vérifications — 4/5 octobre 2026
- `./gradlew check build assemblePack assembleTestPack
-PsanctuaryFocusedTests=base204,demeure,menus,operator,realtime
-PsanctuaryAtlasOnly=true` : succès, tests de logique et 13 GameTests natifs
ciblés. Ces GameTests vérifient notamment l'absence de Test et de Demeure
séparé, les presets publics/historiques, les empreintes Demeure et l'amplitude
Peaks réservée au Nord 204. La suite native historique entière n'a pas été rejouée.
- `:sanctuary:runClientGameTest -PsanctuaryClientTests=true
-PsanctuaryClientGraphicsBackend=vulkan -PsanctuaryShared196ClientTests=true` :
`SHARED196_CLIENT_PASS`, sans Test chargé. FR/EN, tailles, Annuler/Échap,
relecture des paramètres sauvegardés et éditeur Plat vanilla vérifiés.
- Création sur le classpath de production sans Test, heap 2048 Mio : Small
graine 42, Medium graine 0 et Large graine 4736390610738281858. Les trois
serveurs atteignent l'état prêt et placent le spawn sur l'île. Journaux dans
`build/base204-standalone/`. Ce ne sont pas des mesures comparatives de performance.
- Nord natif Small 42, profil 204 : offrande réelle, rejet des mauvaises offres
et doublons, interruption puis reprise du journal, arrivée/relais et cinq
igloos dont une cave vérifiés. Centre de l'expansion `(-128, -944)` ; arrivée
`(-112, 308, -1056)`. L'annonce SGA est émise après préparation.
- Échantillonnage du Nord : sommets Y=103–455, épaisseur maximale 381 blocs ;
prairie, taïga, forêt ancienne, neige, pics, glacier et roche présents.
Dans les chunks inspectés autour de `(-256, 283, -848)`, le plus grand tronc
mesure 60 blocs. Glace et air vérifiés dans une caverne ; glacier vérifié
autour de `(-80, 303, -1120)`. Reçus `build/worldgen-lab/north204-a/small/42/`.
- MRpack normal `Sanctuary-beta.204.mrpack` exporté et ZIP vérifié : Minecraft
26.3, Loader 0.19.5, Fabric API 0.160.5+26.3 ; ni JAR Test ni Demeure séparé.
SHA-256 : `8c90090a784bd7c799849e916be2e3e36214a3dbf6ce8b4925d31a9fca8c5086`.
## Limites et livraison
Les essais natifs du nouveau Nord couvrent la graine 42. Son aspect reste à
évaluer en visite, et la recherche d'un village n'a pas été vérifiée sur toutes
les graines. Ces résultats macOS/Vulkan ne constituent pas une validation Windows.
L'hydrologie du Nord reste à reprendre sur son relief Peaks si l'on souhaite
rétablir de grands lacs. Aucun ancien monde, chunk ou format de sauvegarde n'a
été migré ; les nouvelles formes nécessitent un nouveau profil 204.
Artefact local dans `build/` et copie dans `~/Downloads/`. Une copie indépendante
du monde de test est ouverte pour la visite `north204-visit`, en créatif,
commandes autorisées et vue 32 chunks (`NORTH204_VISIT_OPEN`, Vulkan confirmé).
Aucun packwiz public, serveur personnel
ou instance Prism n'a été mis à jour par ce chantier.
+114
View File
@@ -0,0 +1,114 @@
# Diagonales : transitions, dessous et cavités — beta.227
Retour R045 sur beta.226, 5 octobre 2026. Branche `codex/diagonal-caves-beta227`,
base `5fb1407`. Anciennes générations conservées ; nouveaux profils 227 uniquement.
- NE jardin pâle/marais : transitions d’étangs sans paliers brutaux, relief 3D
plus présent à l’intérieur, fragmentation prononcée du pourtour, petites
échappées d’eau admises mais pas de rideau d’eau massif.
- SO : surface désert/savane appréciée ; retirer de l’épaisseur rocheuse inutile
sous le plateau sans refaire sa surface.
- SE : mangroves et silhouette validées ; ajouter de grandes régions de lush
caves et dripstone caves dans les parties inférieures.
- NO : grandes plaines validées ; commencer le grignotage 3D plus près du centre.
Captures consultées dans le labo 226 : `2026-10-05_21.05.12.png` et
`2026-10-05_21.07.21.png`. Elles montrent des fonds d’étangs à transitions nettes.
La profondeur binaire et le masque de protection des bassins dans 226 sont
remplacés par des transitions continues. La photo seule ne prouve pas un
problème de frontière de chunk ; les contrôles ci-dessous portent sur les
transitions du champ et la décoration native.
## Réalisation
Les champs 225/226 restent figés. 227 s’appuie sur le champ 226 pour conserver
la surface méridionale et la forme des récifs de mangrove. Aucun changement
de sauvegarde, de génération existante ou de dimension.
NE : retrait du halo binaire autour des lacs ; profondeur interpolée, relief
intérieur continu avant arrondi en blocs, rugosité 3D atténuée près de l’eau.
La bordure entière peut être découpée, y compris les anciens abords protégés.
L’eau n’est placée que sur les fonds encore présents ; pas de remplissage des
grandes failles ouvertes. De petites échappées restent possibles. Il ne s’agit
pas d’une simulation d’hydrologie ni d’un réseau de cascades.
SO : amincissement variable, environ 40 à 64 blocs sous le toit avec irrégularité
3D du dessous. Les 24 blocs supérieurs restent sur le champ accepté. Sur les
grilles de sondage 0/42, environ 49 à 51 % du volume rocheux échantillonné est
retiré ; ce n’est pas un recensement exhaustif de toute l’île.
SE : densité et biomes de surface 226 conservés. Sous la surface, de larges
régions de grottes luxuriantes et à concrétions reçoivent les features natives
26.3 (mousse, lianes lumineuses, fleurs sporifères, argile, grandes concrétions,
stalactites/stalagmites). Plages de placement adaptées à Y=40–320. Aucune
nouvelle lave, forêt d’azalées de surface ou nouvelle distribution de minerais
ajoutée par ces deux biomes de cavités. Les volumes existants servent de support,
sans nouvelle excavation de la silhouette validée.
NO : le masque peut maintenant agir jusqu’à 340 blocs de distance interne
au bord (contre 180), sans modifier le noyau de plaines restant. Le champ
supplémentaire ne fait que retirer de la matière.
## Vérifications
Six GameTests ciblés réussis : transitions NE et relief intérieur sur quatre
graines, extension des découpes NO et centre conservé, surface SO intacte et
volume réduit, champ SE identique et deux vastes biomes souterrains, trois
presets publics, ordre des features, déterminisme après recompilation et
anciens profils lisibles.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal227 -PsanctuaryAtlasOnly=true` réussit
en 4 min 2 s (`build/diagonal227-build.log`).
Les premiers essais natifs 0/42 valident le NE, les arbres immergés et les
décorations des deux types de caves au SE. Ils s’arrêtent sur un contrôle trop
étroit des arbres de savane : un seul chunk de chaque biome, tous sans arbre
complet. Lecture des chunks FULL sauvegardés : 11 troncs / 70 feuilles sur 0,
24 troncs / 214 feuilles sur 42. L’instrumentation élargit désormais la recherche
à d’autres chunks de savane, sans changer la production. Helper recompilé et
exporté ; nouveaux essais isolés `diagonal227-final0` et `diagonal227-final42`
réussis, processus terminés normalement. Les mondes du premier essai restent
intacts. Le helper final est recompilé puis exécuté dans ces deux essais ;
aucun changement de production après le build complet.
Les quatre offres réelles, leur coût, le refus d’un double paiement, la reprise
après interruption et les quatre relais utilisables sont vérifiés sur chaque
graine. Chaque activation prépare 49 chunks FULL. Les arbres natifs sont
présents dans les quatre expansions ; 3 et 7 troncs enracinés dans les marais
peu profonds ont été observés. Les sondages des cavités SE trouvent respectivement
120/171 blocs de décoration lush et 34/30 de pointed dripstone. Ces comptages
prouvent la décoration native dans les chunks examinés, pas sa densité globale.
Les cannes à sucre de l’île principale restent présentes : 42 pieds sur 0,
94 sur 42. Rapports ignorés sous `build/worldgen-lab/diagonal227-final{0,42}`.
## Distribution et visite
MRpack normal : `build/Sanctuary-beta.227.mrpack`, copie dans Downloads.
Minecraft 26.3, Fabric Loader 0.19.5. Archive contrôlée, JAR conforme au build,
trois tailles présentes, aucun module Test ni monde inclus. Les 398 ressources
historiques de worldgen comparées sont identiques à 226 ; seul l’alias public
Sanctuary pointe désormais vers les nouveaux profils.
- SHA-256 MRpack : `5ffa88d0a8d30b17276bda0e644e3406dd2a2bdc7727a27e546320a502adf547`.
- SHA-256 JAR : `e759515e49cd254f41e9ab786478cba02613c560534f77d89b820f69ae384dee`.
Nouvelle visite isolée `diagonal227-final-visit`, monde
`Sanctuary-Diagonal-227-0` : copie du nouveau monde de vérification arrêté,
graine 0, île principale Petit, quatre expansions de 1024 prêtes, créatif avec
commandes, distance 32 chunks et simulation 5. Départ au-dessus du relais NE.
Ouverture confirmée le 5 octobre à 21:33:59 : `DIAGONAL227_VISIT_OPEN`,
position `848, 384, -496`, backend Vulkan confirmé dans
`build/diagonal227-solo.log`. Aucune validation OpenGL.
| Région | Relais X, Y, Z sur la graine 0 |
| --- | --- |
| NE jardin pâle/marais | 848, 336, -496 |
| SE mangroves/cavités | 560, 377, 816 |
| SO savane/désert | -832, 217, 512 |
| NO plaines/taïga | -608, 238, -768 |
Le rendu reste à apprécier par le joueur, notamment les berges très découpées
et l’étendue visible des cavités. Pas de visite complète Moyen/Grand, de mesure
de fluidité ni d’essai Windows revendiqués. Aucun ancien monde modifié, aucun
canal packwiz avancé et aucune installation Prism synchronisée.
+100
View File
@@ -0,0 +1,100 @@
# Diagonales climatiques et cannes à sucre — beta.225
## Contrat
Demande du 5 octobre 2026 : cannes à sucre près de l’eau de Sanctuary Island,
puis quatre expansions diagonales de **1024 blocs** (512 remplacé pendant
le chantier à la demande du joueur). Nord froid, Sud chaud,
Est humide, Ouest sec. Branche `codex/diagonal-islands-beta225`, base `1388d8a`.
- Nord-Est : marais frais, jardin pâle, forêt sombre et taïga.
- Nord-Ouest : meadow, prairies, taïga et bosquets froids.
- Sud-Est : mangroves, jungle et bambou.
- Sud-Ouest : désert, savane et prairies sèches.
Première variante : surfaces étendues, collines, dessous flottant irrégulier,
zones humides fermées dans les dépressions du terrain. Végétation et faune
des biomes natifs 26.3. Relais de continuation conservé. Les quatre cardinales
restent en 1024 avec leur génération validée. Pas de nouvelle structure ici.
Nouveaux profils 225 seulement, dans les trois tailles Sanctuary. Les profils
224 et antérieurs gardent leurs règles et leurs tailles d’expansion. Aucune migration ou régénération de sauvegarde.
Les essais utilisent uniquement des mondes neufs de développement (42 et 0).
Le message SGA et l’aide de visite réservée aux opérateurs sont conservés.
## Implémentation
Champ de relief déterministe, collines à grande échelle, bordure irrégulière et
bruit 3D dans le dessous. Épaisseur variable, de neuf blocs sur les extrémités
à 68 blocs à l’intérieur. Les dépressions humides ont un niveau commun Y=204,
un fond protégé et une couronne de terrain ferme ; aucune simulation
hydrologique supplémentaire. La sélection des biomes est continue dans les
coordonnées du monde et utilise les végétations natives 26.3.
Les offres des ancres diagonales demandent un diamètre 1024 et conservent
l’éventail de placement existant. Préparation limitée à 49 chunks autour du
relais ; le reste se génère à l’exploration. Relais simple de continuation pour
cette première variante. Les monuments régionaux des cardinales sont conservés.
Les cannes réutilisent le plan des berges de surface, après leur aménagement.
Groupes de deux ou trois blocs, sur sol accepté par Minecraft et à côté d’une
eau réellement présente. Écriture limitée au chunk décoré, sans dépendre de
l’ordre de décoration des chunks voisins. Aucun nouveau bassin créé.
## Vérifications
Six GameTests ciblés (`base204,diagonal225`) réussis : trois tailles publiques
sans Test, lecture des anciens profils, biomes et étanchéité sur quatre graines,
reproductibilité aux limites des chunks, éventail directionnel et absence de
collision, conservation des matériaux du volcan, règles de survie des cannes.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal225 -PsanctuaryAtlasOnly=true`
réussit en 3 min 57 s. Log : `build/diagonal225-build.log`.
L’essai natif 42 passe les quatre offres, le paiement, l’interruption/reprise,
les relais et la végétation des quatre directions. 94 pieds de canne observés
sur les berges de l’île principale. Le premier essai 0 a révélé une erreur
**du contrôle** : son premier échantillon de mangrove était sur la berge sèche,
ce qui ne prouvait rien sur l’eau de la dépression. Le contrôle cherche désormais
une colonne réellement immergée et vérifie son fluide natif. Le nouvel essai 0 passe aussi les quatre activations et les contrôles natifs ;
43 pieds de canne observés. La correction ne touche que l’instrumentation du
module Test, recompilée et réassemblée ensuite ; le terrain livré est identique.
| Graine | Nord-Est X/Z | Sud-Est X/Z | Sud-Ouest X/Z | Nord-Ouest X/Z | Cannes |
| --- | --- | --- | --- | --- | --- |
| 42 | 544 / -816 | 816 / 544 | -816 / 512 | -704 / -736 | 94 |
| 0 | 848 / -496 | 560 / 816 | -832 / 512 | -608 / -768 | 43 |
Les huit expansions mesurent 1024 blocs et passent chacune par 49 chunks FULL
préparés. Présence de bois/feuilles natifs dans les quatre directions, mangroves
et bambou à l’Est, cactus dans le désert à l’Ouest. Ces relevés sont locaux,
pas un inventaire exhaustif de chaque île. Reçus ignorés :
`build/worldgen-lab/diagonal225-check42/small/42/{cold,warm}.json` et
`build/worldgen-lab/diagonal225-wet-check0/small/0/{cold,warm}.json`.
## Distribution et limites
MRpack standard vérifié : archive intègre, JAR exact, dépendances 26.3/Loader
0.19.5, trois tailles 225 et 382 ressources historiques de génération identiques
à beta.224 (sauf alias public du preset). Aucun monde ni module Test inclus.
SHA-256 : `b178c15d8a40a1627134c64b343d13d508f9e7c95f85d43a1a88c8769d8e8c0c`.
Le rendu reste à apprécier en jeu. Pas de campagne graphique ou Windows,
ni de nouvelle exploration complète Medium/Large. Pas de changement du canal
packwiz ni de l’installation Prism personnelle. Les mondes de contrôle restent
dans les dossiers de développement ignorés.
## Visite du 5 octobre 2026
À la demande du joueur, nouveau solo `Sanctuary-Diagonal-225-0`, graine 0,
copie du serveur de contrôle arrêté. Les quatre diagonales sont déjà prêtes ;
départ au Nord-Est en 848 / 254 / -496. Vulkan, rendu 32 chunks, simulation 5,
créatif/vol et commandes autorisées. Le client confirme `DIAGONAL225_VISIT_OPEN`.
Ajout du nom Diagonal-225 à la liste du lanceur de visites et à son aide client
optionnelle, compilée avec `:sanctuary-test:exportDuoLaunch`. L’identité des
sources du contrôle a été vérifiée avant ce seul changement de lanceur ;
génération et ressources de production identiques. Les anciens mondes et le
MRpack beta.225 livré restent inchangés. La visite est une copie neuve isolée.
+64
View File
@@ -0,0 +1,64 @@
# Jardins pâles bas et roche jaune — beta.230
Retour R048 sur beta.229, 5 octobre 2026. Base `55df522`, branche
`codex/lower-groves-beta230`. Nouveaux profils uniquement, aucune migration
ou régénération des anciennes cartes.
NE : garder le relief validé et étendre les chênes pâles aux terrasses situées
sous le niveau du plateau, y compris à ciel ouvert. Dripstone dans les parties
inférieures ; marais et lucioles restent sur le plateau. Eau toujours
facultative et conditionnée à une cuvette naturellement fermée.
SO : mêler la roche jaune existante à la pierre normale en masses continues,
en conservant les minerais natifs et les cavités soufre/dripstone.
SE mangroves et NO plaines validés par le joueur, champs de relief conservés.
Le seuil inférieur suit le plafond ondulé du terrain savane (Y=230 ± 18),
avec une bande supérieure de 12 blocs laissée au marais. Il ne suit plus le
sommet local de chaque colonne : une terrasse basse ouverte est désormais un
sol de jardin pâle. Même support 2 × 2 et même dégagement pour les arbres.
Les formations natives de dripstone sont ajoutées au biome pâle inférieur.
Les buissons à lucioles restent exclusivement au-dessus de ce seuil.
La roche jaune est répartie par un bruit volumique lent, sans changer la
forme de la savane. La substitution après décoration ne vise que Stone ;
elle conserve les blocs de minerai, leur voisinage immédiat dans le chunk,
les autres roches, le soufre et le cinabre. Aucune variante de minerai jaune
ajoutée et aucun changement des tags minéraux globaux.
Neuf GameTests ciblés réussis : reliefs conservés, séparation des habitats,
terrasses ouvertes et sols abrités, cuvettes fermées, cavités sèches SO,
substitution réelle de pierre avec conservation des minerais, presets et
ordre des features. Les grilles 0/42 trouvent 274/285 sites de chêne pâle,
dont 216/245 ouverts ; ces chiffres ne sont pas un inventaire de l’île.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal230 -PsanctuaryAtlasOnly=true` réussit
en 2 min 38 s. Contrôles natifs réussis sur 0/42 : quatre activations réelles, paiements et
refus des doubles offres, interruption/reprise, 49 chunks FULL par expansion,
relais utilisables. Les nouveaux mondes de contrôle sont arrêtés normalement.
Au NE, dans les chunks sondés : 38/32 blocs de tronc pâle, quatre colonnes
de racine à ciel ouvert sur chaque graine (un tronc de 2 × 2), 103/76 blocs
de pointed dripstone et 7/1 buissons à lucioles supérieurs. Au SO : les deux
roches sont présentes (462/1711 blocs jaunes et 7180/2707 Stone dans les
échantillons), avec pics de soufre et dripstone. Ces comptes attestent la
présence, sans mesurer la proportion globale sur chaque île.
Rendu à apprécier en jeu.
MRpack normal vérifié, copie dans Downloads : Minecraft 26.3 / Fabric Loader
0.19.5, trois tailles, JAR identique au build, aucun module Test ni monde.
Les 432 ressources historiques de worldgen comparées à 229 sont identiques.
SHA-256 pack : `b080b17d7e54427d3a6b89da2b009637e99a648752ba49068a274fa35499f8e4`.
SHA-256 JAR : `c72cc0afea27e7d71c73d6f4edc4f874bc5fb665288eba243d7faafcba5e3276`.
Reçu : `build/diagonal230-mrpack-receipt.json`.
Aucune publication de canal ni synchronisation Prism, aucune validation
Windows ou mesure de fluidité.
Nouvelle visite isolée `diagonal230-visit`, monde `Sanctuary-Diagonal-230-0`,
copiée depuis le contrôle graine 0 arrêté. Île principale Petit et quatre
expansions 1024 prêtes. Créatif avec commandes, 32 chunks, simulation 5 ;
départ au relais NE (856, 273, -496). Ouverture Vulkan confirmée à 22:45:00
le 5 octobre 2026, `DIAGONAL230_VISIT_OPEN` dans `build/diagonal230-solo.log`.
Le rendu reste à apprécier par le joueur ; anciennes visites conservées.
+110
View File
@@ -0,0 +1,110 @@
# Reliefs distincts des diagonales — beta.226
Retour du 5 octobre 2026 sur beta.225. Biomes appréciés, silhouettes refusées :
grands plateaux identiques, bords tranchés. Branche `codex/diagonal-relief-beta226`,
base `e2b9ee7` et conservation des ajustements locaux du lanceur de visite 225.
- Nord-Est : garder les bassins, davantage de hauts reliefs émergés sans excaver
leur intérieur ; marais moins profonds, arbres plus fréquents dans l’eau,
quelques grands lacs conservés.
- Nord-Ouest : grandes plaines et végétation validées ; bords rongés fortement
en 3D, effet qui diminue en allant vers le centre, centre préservé.
- Sud-Ouest : remplacer la base par un terrain flottant 3D natif, grandes
surfaces de sable et roche, plateaux de savane, léger rehaussement local.
- Sud-Est : relief très fragmenté, hauts et bas, récifs verticaux, davantage
de mangroves ; boue, argile et calcite. Abandon de l’ambiance plate.
Diamètre 1024, Est humide/Ouest sec. Nouveaux profils 226 seulement. Île
principale, cannes à sucre et quatre cardinales conservées. Pas de migration
des mondes 225 ou antérieurs ; nouvelles visites isolées pour les essais.
## Réalisation
La révision 225 reste figée. Trois nouveaux profils 226 réutilisent exactement
la génération de Sanctuary Island ; seules les diagonales passent au nouveau
champ. Les anciennes ressources et leurs identifiants restent lisibles.
Le Nord-Ouest réemploie les colonnes et matériaux 225 à plus de 180 blocs de
la bordure. À l’extérieur, deux échelles de bruit volumique découpent le bord
et le dessous ; un masque continu réduit l’effet en approchant du centre.
Le Nord-Est conserve les dépressions et leur enveloppe étanche, garde une
partie des lacs profonds et relève les autres fonds à une ou deux couches
d’eau. Des reliefs émergés ajoutés en 3D restent à distance des bassins. Les
chênes de marais natifs reçoivent davantage de tentatives de plantation.
Le Sud-Ouest repart du champ flottant `PopulationIslandDensity`, sans le
plateau commun 225, avec une limite haute légèrement ondulée pour les savanes.
Le Sud-Est étire verticalement ce champ, ajoute des fractures et des récifs
volumiques, et favorise les mangroves natives. Les différentes corniches
exposées reçoivent du sol, pas seulement le sommet de la colonne ; les veines
cohérentes de calcite et d’argile traversent la roche. Le sable repose sur une
base solide. Les biomes de végétation natifs restent ordonnés et compatibles.
Les bassins 225 conservés concernent le Nord-Est. Le Sud-Est abandonne ses
anciens bassins plats ; ses mangroves poussent sur les corniches de boue.
La préparation d’une expansion reste limitée à 49 chunks autour du relais.
Pas de passe d’hydrologie ou de simulation supplémentaire, ni de nouvelle
structure. Relais cherché sur un support réel ; le petit socle 3 × 3 existant est conservé,
sans grande terrasse artificielle.
## Contrôles
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal226 -PsanctuaryAtlasOnly=true` réussit
en 2 min 42 s (`build/diagonal226-build.log`). Six GameTests : trois profils
publics et historiques, conservation du centre NO, bords rongés, bassins NE
étanches et moins profonds sur quatre graines (0, 42, 2026, -9137), volumes
natifs méridionaux, part des mangroves, déterminisme après recompilation,
relais supportés, ordre des features et routage des cardinales validées.
Sur la grille de contrôle des deux graines 0/42, le NO perd plus de la moitié
de ses colonnes de bord à leur ancienne hauteur, avec un centre strictement
conservé. Le NE conserve des lacs profonds et 56 à 84 % de colonnes humides
peu profondes sur les quatre graines. Les reliefs ajoutés dépassent localement
85 blocs. Au SE, la mangrove couvre 67 à 73 % des colonnes émergées échantillonnées
sur les graines de champ 0/42 ; les surfaces vont localement de Y=63 à Y=439.
Ce sont des sondages de champs, pas des mesures exhaustives des mondes.
Deux mondes natifs neufs, graines **0 et 42**, passent les quatre offres réelles,
le refus des paiements incorrects et doubles offres, l’interruption après
réservation, la reprise, les relais utilisables et la décoration native.
Chaque préparation reste à 49 chunks FULL. Trois troncs natifs enracinés
sous le niveau de l’eau ont été constatés dans le marais de chaque monde
(arrêt du contrôle dès trois arbres). Bois et feuilles présents sur les quatre
îles, mangroves sur les corniches SE. Cannes de l’île principale : 42 pieds
sur 0, 94 sur 42. Les relevés de plantes portent sur quelques chunks par biome ;
un échantillon désert sans cactus ne constitue pas un inventaire de l’île.
Reçus ignorés :
`build/worldgen-lab/diagonal226-check0/small/0/{cold,warm}.json` et
`build/worldgen-lab/diagonal226-check42/small/42/{cold,warm}.json`.
## Distribution
MRpack standard beta.226 dans `build/` et `~/Downloads/`, contrôlé après
assemblage : archive intègre, JAR construit exact, Minecraft 26.3 / Loader
0.19.5, trois nouveaux profils et 388 ressources historiques de génération
identiques à beta.225 (hors alias public). Aucun monde ou module Test inclus.
SHA-256 : `c1ce5fc71a3e0417194d591d1ddd04b00dcef46565dfdb34ccd7ee2a01217e02`.
Pas de publication du canal packwiz, de push ou de modification de Prism.
Les mondes existants restent sur leur révision. Rendu à apprécier par le joueur ;
pas de campagne de screenshots, de validation Windows ou d’exploration complète
Medium/Large. Les contrôles des trois tailles vérifient leurs registres et presets.
## Visite
Copie isolée du serveur 0 arrêté dans
`build/worldgen-lab/diagonal226-visit/small/0/client/saves/Sanctuary-Diagonal-226-0`.
Créatif, vol et commandes autorisés ; 32 chunks de rendu, simulation 5,
mémoire 4 Gio. Départ NE à 848 / 270 / -496. Vulkan confirmé ; `DIAGONAL226_VISIT_OPEN` le 5 octobre à 20:32:59.
Le joueur passe en Spectateur à 20:33:04.
Points d’observation libres, téléportation possible :
- NE : `/tp @s 848 270 -496`
- SE : `/tp @s 560 425 816`
- SO : `/tp @s -832 265 512`
- NO : `/tp @s -608 286 -768`
+88
View File
@@ -0,0 +1,88 @@
# Diagonales : abaisser et ciseler — beta.228
Retour R046 sur beta.227, 5 octobre 2026. Base `70a34df`, branche
`codex/diagonal-shaping-beta228`. Nouveaux profils uniquement.
Le jardin pâle monte trop haut entre les étangs. Conserver son pourtour 3D,
abaisser fortement le relief et rendre les lacs lisibles. Les mangroves et
leurs cavités conviennent, mais leurs volumes demandent des arêtes moins
rondes. Même finition sur les bordures des plaines NO, plateau général
conservé. L’épaisseur et la surface désert/savane SO sont validées et figées.
Captures consultées dans le labo 227 : `2026-10-05_21.36.56.png` et
`2026-10-05_21.40.07.png` ; grandes buttes NE et découpe arrondie NO visibles.
## Réalisation
NE : comprimer les hauteurs émergées, réduire la surélévation et l’annuler sur
les fonds aquatiques. SE/NO : fractures Voronoi à largeur modulée par du bruit
3D ; calcul cellulaire mis en cache par colonne. Le noyau de plaines NO et le
champ SO restent ceux de 227. Réutiliser les deux biomes de cavités 227 au SE.
La partie émergée du NE est comprimée à 55 % de sa hauteur au-dessus de l’eau.
Les deux surélévations passent de 120 + 100 à 12 + 8 blocs, avec une transition
continue qui les annule sur les fonds aquatiques. Le masque 3D du bord reste
celui de 227. L’eau garde son niveau Y=204, sans nouvelle simulation hydrologique.
Le Voronoi SE/NO fournit la distance aux faces des cellules ; deux bruits 3D
modulent la largeur des fractures à différentes échelles. Le calcul cellulaire
est réutilisé sur la colonne entière. Au NO, l’action supplémentaire cesse
à 280 blocs de distance interne au bord : le centre est exactement celui de
227. Au SE, seules des découpes sont ajoutées ; les cavités existantes ne sont
pas remplies. Les nouveaux rebords reçoivent les matériaux du terrain 226.
## Vérifications
Sept GameTests ciblés réussis (`build/diagonal228-tests.log`). Sur les grilles
NE de quatre graines, dont les deux graines d’expansion réellement visitées :
sommets entre Y=228 et 237, baisse moyenne intérieure de 30 à 39 blocs,
2,4 à 2,6 fois plus de colonnes en eau qu’en 227. Plus de 95 % des anciens fonds
aquatiques 225 du centre sont de nouveau en eau. Ce sont des échantillons,
pas une mesure exhaustive de la superficie des lacs.
Sur 0/42, environ 8–10 % de matière en moins au NO et 22 % au SE dans les
grilles sondées ; centre NO conservé, deux biomes de caves présents, relais
sur support, surfaces de mangrove préservées comme habitats. Le champ de
densité et les matériaux SO sont identiques à 227 sur les échantillons.
Déterminisme, trois presets publics et anciens identifiants contrôlés.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal228 -PsanctuaryAtlasOnly=true` réussit
en 2 min 43 s (`build/diagonal228-build.log`), avec les sept GameTests.
Contrôles natifs réussis sur deux nouveaux mondes isolés, graines 0/42 :
`diagonal228-check0` et `diagonal228-check42`. Paiements et refus des doubles
offres, interruption/reprise, quatre expansions de 1024, 49 chunks FULL par
activation et relais utilisables vérifiés. Les sondages trouvent des arbres
dans chaque région, ainsi que des troncs enracinés dans l’eau au NE (3/7).
Au SE, présence native des décorations lush (389/114 blocs échantillonnés) et
pointed dripstone (38/76). Ces comptages ne mesurent pas leur abondance globale.
Les deux processus se terminent normalement. Aucun ancien monde modifié.
## Artefact local
MRpack normal `build/Sanctuary-beta.228.mrpack`, copié dans Downloads.
Archive et JAR vérifiés, Minecraft 26.3 / Fabric Loader 0.19.5, trois tailles,
aucun module Test ni sauvegarde dans le pack. Les 415 ressources historiques
de worldgen comparées à 227 sont identiques ; seul l’alias public est avancé.
- SHA-256 MRpack : `5e808121a2b1e3e358c58a2bb4616592521a4bd54cb18fe25c3ab68b05a4ee9d`.
- SHA-256 JAR : `4a62259e1d941079de44237ed3a342a5a5e7fbe443fce07826fda76be2dd2a58`.
Nouvelle visite `diagonal228-visit`, monde `Sanctuary-Diagonal-228-0`, copiée
depuis le nouveau monde de contrôle arrêté. Graine 0, île principale Petit,
quatre expansions de 1024 prêtes, créatif avec commandes, 32 chunks et simulation
5. Ouverture Vulkan confirmée le 5 octobre à 21:54:28 dans
`build/diagonal228-solo.log` : `DIAGONAL228_VISIT_OPEN`, position 848, 267, -496.
| Région | Relais X, Y, Z sur la graine 0 |
| --- | --- |
| NE jardin pâle/marais | 848, 219, -496 |
| SE mangroves/cavités | 560, 377, 816 |
| SO savane/désert | -832, 217, 512 |
| NO plaines/taïga | -608, 238, -768 |
Le rendu reste à apprécier par le joueur. Ces essais ne constituent pas une
mesure de fluidité ni une visite exhaustive des tailles Moyen/Grand. Aucun
essai Windows, aucune modification d’un ancien monde, aucune publication de
canal packwiz ou synchronisation Prism dans ce chantier.
+76
View File
@@ -0,0 +1,76 @@
# Sous-bois pâles et visite des neuf îles — beta.231
Retours R049–R050 du 5 octobre 2026. Base `42e42fe`, branche
`codex/pale-understory-beta231`. Correctif livré ; nouvelle visite ouverte.
Compléter les sols inférieurs du jardin pâle : herbes, fleurs natives
(eyeblossoms), tapis et mousse suspendue sous les feuillages. Conserver les
formes, arbres, dripstones, marais supérieurs et géologie de savane validés.
L’eau reste facultative, seulement dans les cuvettes naturelles existantes.
Nouvelle révision de génération, sans modifier les anciens profils ou mondes.
Préparer une nouvelle visite isolée sur la graine 0 : Sanctuary Island Grand
(1024 blocs), huit expansions de 1024, toutes activées. Le joueur a choisi ensuite une ouverture immédiate,
avec chargement des zones restantes pendant l’exploration. Créatif, commandes, Vulkan, distance 32 chunks. Aucun changement
à la génération normale du rythme d’ouverture des expansions. Pas de
publication de canal, ni modification de l’instance Prism personnelle.
Le correctif réutilise exactement le champ de terrain 230 et ses biomes.
Une décoration supplémentaire parcourt les sols inférieurs réels du NE,
à ciel ouvert ou abrités : herbe courte/haute, tapis de mousse pâle et fleurs
fermées natives, avec leur transition jour/nuit. Petits rideaux de mousse
sous le feuillage pâle. Les regroupements suivent des bruits lents ; aucune
plante ne remplace eau, roche, tronc, dripstone ou végétation existante.
Cinq GameTests passent, dont support réel des plantes, double hauteur,
protection des obstacles et conservation du champ accepté sur 0/42.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal231 -PsanctuaryAtlasOnly=true` passe
en 2 min 34 s. MRpack normal vérifié (Minecraft 26.3 / Loader 0.19.5), trois
tailles, JAR exact, sans Test ni monde ; 439 ressources historiques identiques.
SHA-256 pack : `3a9763cb81e088a0beeb4e4044dd35586a590c75f6c2f9a035937c8df4dee14c`.
SHA-256 JAR : `8ba7b19428094e01ac9f3b6b3f8054343bc7a3df60f786260f01b487ee2f675a`.
Copie `Downloads/Sanctuary-beta.231.mrpack`, reçu
`build/diagonal231-mrpack-receipt.json`.
La préparation complète est explicite :
`python3 scripts/worldgen_lab.py verify --run archipelago231-check0 --profile large
--seed 0 --checks diagonal231 --all-islands --memory 2048`.
Elle utilise les paiements natifs, conserve l’interruption/reprise du premier
relais, puis charge les neuf emprises avec une limite de quatre chunks en
cours. Chaque chunk doit atteindre FULL, tickets libérés au fur et à mesure.
Rapport final et arrêt propre requis avant de copier la nouvelle visite.
Sur la graine 0 en Grand, les quatre contrôles natifs des diagonales passent :
NE, dans un chunk inférieur sondé, 75 blocs d’herbe, 24 fleurs, 37 tapis,
8 mousses suspendues, 44 troncs pâles, 105 dripstones et 5 lucioles supérieures.
Ces nombres attestent leur présence ; ils ne mesurent pas toute l’île.
Savane : 7731 blocs jaunes et 101 de pierre dans les échantillons ; cavités
soufre/dripstone présentes. Mangroves et plaines conservent leurs habitats.
Les huit activations réelles aboutissent, relais présents, journal relu :
neuf îles de diamètre 1024 en état `ready`, génération 231, graine racine 0.
La prégénération intégrale visait 41 458 chunks ; le joueur choisit de lancer
le solo immédiatement. Arrêt demandé à 23:06:09, sauvegarde normale achevée,
dernier jalon 256/41 458 (en plus des zones d’arrivée et échantillons).
Ce contrôle interrompu volontairement n’est **pas** une prégénération complète
réussie ; les zones restantes se chargent pendant l’exploration.
Reçu : `build/worldgen-lab/archipelago231-check0/large/0/visit-readiness.json`.
Anciennes visites conservées, aucune validation Windows ou mesure de fluidité.
Visite `archipelago231-visit/large/0`, monde `Sanctuary-Diagonal-231-0`,
créée depuis le serveur arrêté et ouverte à 23:07:33 le 5 octobre 2026.
Vulkan confirmé, marqueur `DIAGONAL231_VISIT_OPEN`, départ (0, 320, 0),
créatif/vol/commandes, rendu 32 chunks, simulation 5. Les données du labo
restent dans `build/` ignoré. Aucun ancien monde modifié.
| Île | Centre X/Z | Commande de visite |
| --- | --- | --- |
| Nord | 32 / -1984 | `/sanctuary expansion visit r2yyuk27a85c8p` |
| Nord-Est | 736 / -960 | `/sanctuary expansion visit r7vapqz7anv7c` |
| Est | 1776 / -208 | `/sanctuary expansion visit r2zwcc9ktr14ds` |
| Sud-Est | 960 / 736 | `/sanctuary expansion visit r3bswui5wc00kk` |
| Sud | 0 / 1536 | `/sanctuary expansion visit r391kr4y3lwlzy` |
| Sud-Ouest | -960 / 736 | `/sanctuary expansion visit rclt83rncgsv1` |
| Ouest | -1792 / -192 | `/sanctuary expansion visit r3r7b6q184g2a1` |
| Nord-Ouest | -736 / -960 | `/sanctuary expansion visit r81ebztggj346` |
+97
View File
@@ -0,0 +1,97 @@
# Marais étagé et cavités sèches — beta.229
Retour R047 sur beta.228, 5 octobre 2026. Base `b77d71b`, branche
`codex/wetland-reset-beta229`. Nouveaux profils uniquement ; aucun ancien
monde, chunk ou identifiant de génération migré.
## Contrat
Refaire entièrement le NE : même géométrie que la savane amincie validée,
chênes pâles sur les sols abrités sous la roche, marais en haut. Lucioles
uniquement dans le marais supérieur. Eau facultative, seulement quand le
relief possède une dépression fermée ; abandon des lacs à niveau constant.
SO : soufre et dripstone dans les parties inférieures, sans lush caves et
sans changer la surface. SE mangrove entièrement validé ; NO conservé
provisoirement malgré les réserves esthétiques, aucune retouche des deux.
## Implémentation
Le NE réutilise le champ de densité SO 228, avec la graine propre à cette
expansion. Épaisseur variable et plateau restent ceux de ce champ ; seules
les matières et les habitats changent. Sous les 12 derniers blocs du toit,
biome jardin pâle ; en haut, biome marais. Plantation native des chênes pâles
sur des sols naturels de 2 × 2 avec le dégagement nécessaire sous un surplomb.
Les buissons à lucioles sont posés sur le sol supérieur réel, jamais sur des
feuilles ni dans le jardin pâle inférieur.
Aucune simulation hydrologique ni construction de cuvette : une recherche
locale bornée accepte seulement des dépressions d’un bloc de profondeur,
avec deux blocs de fond solide et des murs naturels continus. Si une paroi
manque, toute la mise en eau est abandonnée. Ces mares peuvent être rares
ou absentes suivant la graine. Les biomes NE n’ajoutent aucune source native.
SO : régions de soufre/cinabre ou dripstone sous le plateau, dans les
cavités du terrain existant. Formations natives de pics de soufre et de
speleothèmes ; aucun creusement nouveau ni décor lush. Les deux autres
champs et leurs décorations restent en révision 228.
## Vérifications
Huit GameTests ciblés passent (`build/diagonal229-tests.log`). Sur les graines
0/42, identité du champ NE avec le SO 228, habitats séparés en hauteur,
65/46 emplacements de chênes pâles sur les grilles sondées, mares toutes
bordées de matière naturelle, déterminisme, cavités SO et conservation des
champs SE/NO contrôlés. Les nombres d’emplacements ne représentent pas un
inventaire exhaustif des arbres de l’île.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,diagonal229 -PsanctuaryAtlasOnly=true` réussit
en 2 min 38 s. Contrôles natifs 0/42 réussis, avec quatre offres réelles,
refus des doubles offres, consommation correcte, interruption/reprise,
49 chunks FULL par activation et relais utilisables.
Dans les chunks sondés au NE : 40/44 blocs de tronc pâle et 9/4 buissons à
lucioles supérieurs ; racines sous des surplombs et aucune luciole basse.
Au SO : 32/37 pics de soufre et 9/76 pointed dripstone ; aucun décor lush
trouvé dans les cavités inspectées. Ces chiffres attestent la présence,
pas l’abondance globale. Les cavités lush/dripstone SE restent présentes.
Lecture des deux sauvegardes arrêtées (`build/diagonal229-water-audit.json`) :
52/51 chunks NE FULL, 36/12 colonnes de racines pâles, aucune cellule d’eau.
Les rares mares du plan théorique n’étaient donc pas présentes dans cet
échantillon natif ; leur fréquence visuelle reste à apprécier ailleurs.
Aucun ancien monde n’a été modifié.
## Artefact local
MRpack normal `build/Sanctuary-beta.229.mrpack`, copie dans Downloads.
Archive et JAR construits vérifiés, Minecraft 26.3 / Fabric Loader 0.19.5,
trois tailles publiques, aucun module Test ni sauvegarde. Les 421 ressources
historiques de worldgen comparées à 228 sont identiques ; seul l’alias public
est avancé. Reçu : `build/diagonal229-mrpack-receipt.json`.
- SHA-256 MRpack : `788b3aa5898f12aed4570224beb4dd44505eb9e5cae89cefdef9fe7549c85f8b`.
- SHA-256 JAR : `50fd7d6c04c9060abf3eca89bbaf936b39c6e9e82051d2d6559f197f425fdda9`.
Aucune validation Windows ni mesure de fluidité. Aucun ancien monde modifié,
aucune publication du canal packwiz ni synchronisation Prism.
## Visite
Nouvelle visite isolée `diagonal229-visit`, monde `Sanctuary-Diagonal-229-0`,
copiée depuis le nouveau contrôle graine 0 arrêté. Île principale Petit,
quatre expansions de 1024 prêtes, créatif avec commandes, vue 32 chunks,
simulation 5. Ouverture Vulkan confirmée à 22:23:49 le 5 octobre 2026 :
`DIAGONAL229_VISIT_OPEN` dans `build/diagonal229-solo.log`. Rendu à apprécier
par le joueur.
| Région | Relais X, Y, Z sur la graine 0 |
| --- | --- |
| NE marais / jardin pâle inférieur | 856, 225, -496 |
| SE mangroves / cavités | 560, 377, 816 |
| SO savane / cavités sèches | -832, 217, 512 |
| NO plaines / taïga | -608, 238, -768 |
Exemple de pied de chêne pâle observé dans la sauvegarde : 475, 174, -541.
Le joueur démarre au-dessus du relais NE. Anciennes visites conservées.
+84
View File
@@ -0,0 +1,84 @@
# Est — cratère strié et arbres enracinés, beta.224
## Contrat du 5 octobre 2026
Retour après visite beta.223 : relief général, arbres et ravins appréciés.
Arbres de jungle observés sur d’autres arbres ; cratère jugé trop camouflage.
Conserver la géométrie et retravailler ses matériaux : lignes concentriques
du fond vers le sommet, stries verticales/hachures qui s’estompent en hauteur,
plus d’obsidienne, magma à proximité, transitions légèrement bruitées.
Captures évoquées sans chemin fourni : aucune capture inspectée.
Branche `codex/east-crater-beta224`, base `9063e16`.
## Portée
Nouveaux profils 224 uniquement. Le champ de densité, les hauteurs, ravins,
cavités, lave et emplacements de monuments reprennent exactement 223 pour une
même graine d’expansion. Habillage minéral de la surface et des sept blocs sous-jacents du
cratère uniquement, sans nouvelle simulation ni passe de relief.
Les grandes jungles utilisent les mêmes arbres avec un filtre de sol avant
plantation, absent du placement custom 223. Tables natives de bambou, pandas
et autres arbres conservées. Île principale, Nord, Sud et Ouest conservés.
Anciennes sauvegardes et profils intacts ; essai dans un nouveau laboratoire.
## Vérifications ciblées
Java 25, Minecraft 26.3, Fabric Loader 0.19.5 et API 0.160.5+26.3.
Sept GameTests réussis (`base204,east223,east224`) :
- Conservation exacte des hauteurs, densités, cavités et volumes de lave entre
223 et 224 sur quatre graines d’expansion ; aucun déplacement des monuments.
- Matériaux hors du traitement du cratère inchangés ; obsidienne plus abondante
et magma présent sur la rive découverte, pas seulement sous la lave.
- Admission du grand arbre refusée sur feuilles, troncs, air et pierre ;
admise sur herbe, terre et podzol. Le tag natif `minecraft:dirt` de 26.3
ne contient ni herbe ni podzol : le filtre utilise les sols explicites et
la règle native de survie du jeune arbre, testés depuis le registre chargé.
- Profils de création et anciens profils chargés, anciens contrôles Est 223
et conservation de l’Ouest validé.
Deux serveurs natifs isolés à 2 Gio passent la demande par ancre, le refus du
mauvais paiement, l’interruption/reprise et la préparation de 62 chunks.
Même position et graine d’expansion qu’en 223 ; diamètres 1024 :
| Graine monde | Centre X/Z | Graine expansion | Tronc maximal | Pieds suspendus détectés |
| --- | --- | --- | --- | --- |
| 42 | 944 / 144 | 207124680538740498 | 41 blocs | 0 |
| 0 | 944 / -144 | 118376680751547919 | 44 blocs | 0 |
La recherche de pieds suspendus porte sur 24 chunks par graine (huit par
ambiance de jungle) : terre située plus de cinq blocs au-dessus du terrain
avec un tronc dessus. Ce contrôle et le filtre de placement corrigent le cas
identifié ; ils ne constituent pas une inspection exhaustive de tous les arbres.
Les mêmes relevés comptent respectivement 840/1 565 bûches, 2 883/4 646 feuilles
et 2 748/2 094 bambous. Deux coffres à butin et deux distributeurs dans chaque
temple, relais complet, 919/957 colonnes de lave et 39 464/38 928 contrôles
de parois sans fuite.
Reçus ignorés : `build/east224-gametest-passed.log` et
`build/worldgen-lab/east224-checked{42,0}/small/{42,0}/{cold,warm}.json`.
## Livraison
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,east223,east224 -PsanctuaryAtlasOnly=true`
réussit en 5 min 25 s. Log : `build/east224-build.log`.
MRpack normal vérifié et copié dans `~/Downloads` : archive intègre, JAR exact,
trois tailles, filtre de plantation et 371 ressources de génération historiques
strictement identiques à beta.223 (hors alias public du preset). Aucun monde ni
module de test embarqué. Reçu : `build/east224-mrpack-receipt.json`.
SHA-256 de `Sanctuary-beta.224.mrpack` :
```text
01aed4e6a0d9e2965ed8201372eef3aaecab3b0c6dce3fb84586895ed9076885
```
La visite neuve `Sanctuary-East-224-42` est ouverte le 5 octobre à 17:26:25,
Vulkan natif, rendu 32 chunks, simulation 5, créatif/vol/commandes. Position
initiale 547 / 351 / 144, face au volcan. Copie du serveur de contrôle arrêté,
identité de sources vérifiée ; anciennes visites conservées.
Le rendu des stries reste à apprécier par le joueur. Pas de nouvelle campagne graphique Windows,
ni d’exploration complète Medium/Large. Aucune modification d’ancien monde,
publication de canal ou mise à jour Prism.
+85
View File
@@ -0,0 +1,85 @@
# Est — volcan flottant et jungles, beta.223
## Contrat du 5 octobre 2026
Après la livraison des déclinaisons de roche jaune (beta.222), le joueur valide
l’Ouest 221 et demande le laboratoire Est. Volcan actif, lave dans le cratère,
jungle sur les flancs ; la silhouette historique est explicitement rejetée.
Il faut un vrai cône volcanique flottant, un temple de jungle, du bambou,
des pandas et des jungles clairsemées ou denses avec de très grands arbres.
Diamètre de premier essai : 1024 blocs, dans la direction de l’ancre Est.
Branche `codex/east-volcano-beta223`, base `2d656d9`.
## Portée
Nouveaux profils 223 Small/Medium/Large uniquement ; aucun profil 222 de
terrain n’existe (222 ajoutait uniquement des blocs). Île principale, Nord,
Sud et Ouest conservent leurs générateurs validés. Les mondes et journaux
historiques sont conservés. Nouveau laboratoire et nouvelle activation ;
aucune expansion ajoutée à une sauvegarde personnelle.
Silhouette conique asymétrique, bouche décentrée et légèrement elliptique,
ravines ramifiées par bruit cohérent, épaulement ancien et affaissement local
du bord du cratère. Répartition des jungles par nappes de bruit, sans secteurs
radiaux répétés. Couronne sommitale irrégulière et cuvette de lave
fermée, dessous suspendu irrégulier. Roche volcanique au sommet, sol végétal
sur les flancs. Biomes de jungle et bambou avec végétation native, dont une
variante de grands arbres. Temple natif avec pièges et coffres, fondations
locales. Relais sur le flanc extérieur, éloigné du cratère.
Pas d’éruption animée ni de simulation géologique/hydrologique globale.
## Vérifications
Le 5 octobre 2026, Java 25, Minecraft 26.3 et Fabric Loader 0.19.5 :
- `./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,east223,rock222 -PsanctuaryAtlasOnly=true`
réussit en 3 min 34 s. Sept GameTests ciblés passent également lors du contrôle
préalable : profils historiques et actuels, roche jaune, forme et lave sur
quatre graines, direction Est, égalité du relief et des décors Ouest 221/223.
- Deux serveurs natifs isolés, graines 42 et 0, mémoire 2 Gio : demande par ancre,
refus du mauvais paiement, interruption à 0/62 chunks et reprise persistée.
Les deux expansions deviennent disponibles avec 62 chunks préparés ; la suite
est générée à l’exploration.
- La cuvette est contrôlée dans les chunks réels : 919/957 colonnes de lave et
39 464/38 928 vérifications de parois pour 42/0. Aucun débouché vers le vide
détecté dans ces contrôles.
- Chaque temple contient deux coffres à table de butin et deux distributeurs
piégés ; 1 157 blocs de maçonnerie relevés. Le relais possède ses 2 069 blocs
attendus et une offre utilisable.
- Sur 24 chunks par graine, huit de chaque ambiance de jungle : 1 501/1 446
bûches, 3 747/4 398 feuilles, 2 689/2 294 bambous ; tronc continu maximal de
44 blocs sur les deux graines. Les tables natives du biome bambou comprennent
les pandas ; leur nombre réel n’est pas une assertion de cette campagne.
- MRpack vérifié : ZIP, JAR exact, versions, trois tailles, profils historiques,
biomes Est, tables de pandas, grands arbres, temple et déclinaisons de roche
jaune ; aucun monde ni module de laboratoire embarqué.
Les logs et reçus ignorés sont `build/east223-build-final.log`,
`build/east223-natural-gametest.log`, `build/east223-mrpack-receipt.json` et
`build/worldgen-lab/east223-checked{42,0}/small/{42,0}/{cold,warm}.json`.
| Graine du monde | Centre de l’expansion X/Z | Graine de l’expansion | Temple X/Y/Z |
| --- | --- | --- | --- |
| 42 | 944 / 144 | 207124680538740498 | 835 / 271 / 418 |
| 0 | 944 / -144 | 118376680751547919 | 961 / 300 / 150 |
## Livraison et visite
`Sanctuary-beta.223.mrpack`, copié dans `~/Downloads`, SHA-256 :
```text
ac31ff8203dca95265c7d0af545bab231697ad295b48eade2ee115090a9597e6
```
La visite neuve `Sanctuary-East-223-42` est ouverte le 5 octobre à 17:09:45,
Vulkan natif, rendu 32 chunks, simulation 5, créatif/vol/commandes. Position
initiale 547 / 351 / 144, face au volcan. Copie du laboratoire arrêté,
identité de sources vérifiée ; les anciennes visites sont conservées.
La roche jaune, ses escaliers et dalles de beta.222 sont inclus.
Le rendu naturel reste à apprécier par le joueur : les contrôles numériques
ne constituent pas une validation esthétique. Essais natifs Small sur deux
graines ; Medium/Large sont assemblés et leurs profils vérifiés, sans nouvelle
campagne d’exploration complète. Aucun essai Windows ni simulation d’éruption.
Pas de publication du canal packwiz ni de mise à jour de l’instance Prism.
+85
View File
@@ -0,0 +1,85 @@
# WG-ERODED-192 — couronnes et faces du massif
Branche `codex/eroded-massif-beta192`, Minecraft 26.3, graine de visite 42.
Profil `eroded`, preset neuf `sanctuary_test:eroded_massif_v1`.
## Retour et résultat attendu
Après la restauration beta.191, les captures du 30 septembre à 22:02–22:05
montrent des marches de terre et d’herbe sur les sommets arrondis. Le créateur
souhaite de vrais changements de forme : quelques dessus plus plats sous les
arbres, des faces plus franches, des creux d’érosion et des pentes conservées.
Ne pas reproduire les terrasses périodiques 189 ou simplement peindre la roche.
## Variante
Trois couronnes sont choisies dans les points hauts du massif existant. Leur
altitude dépend du terrain original. Les trois cerisiers réservés occupent ces
couronnes, avec exclusion des points de plantation encore trop raides. Une coupe légèrement inclinée rabote le
sommet ; une face plus raide regarde son versant descendant. Les empreintes
ont des limites adoucies et irrégulières ; les petites entailles entre couronnes
s’appuient sur la distance aux deux centres de Voronoï les plus proches.
Les coupes retirent au plus 24 blocs du plafond géométrique local. Une cavité
préexistante découverte par la coupe peut donner un sol visible plus bas.
C’est une érosion géométrique locale sur le bruit 3D existant, sans simulation
physique. Pas de grille de niveaux Y, de remplissage des cavités ni de lissage
global. Aucun changement de densité à Y≤240, dans les îlots aériens ou hors du
massif central. Les formes originales restent la base sous le plafond sculpté.
La couverture végétale du massif n’est posée que sur les surfaces capables de
la porter : les fortes pentes gardent la géologie réelle (stone, gisements,
strates). Le gradient est mesuré sur des colonnes du massif en coordonnées
monde, traversant les limites des chunks et ignorant les îlots aériens. Les
hauteurs et pentes sont mises en cache dans un domaine borné. Cette variante
n’utilise pas le solveur d’hydrologie ; les étangs et déversoirs existants restent
responsables de l’eau.
Ancres, donjon, gemmes, soufre, ruines à coffres, galerie, rosace et palais sont
conservés. La règle de roche historique garde son comportement lorsque son
nouveau champ optionnel `slope` est absent. Les anciens presets gardent leurs
paramètres ; aucun monde existant n’est modifié ou régénéré.
## Vérifications et limites
Génération native finale et réouverture réussies, graine 42 :
`build/eroded192e-cold.json` et `build/eroded192e-warm.json`.
Les hauteurs mesurées sont identiques après rechargement ; les trois troncs
sont relus dans les chunks sauvegardés.
- 1 008 colonnes modifiées dans le relevé espacé de deux blocs ; 392 échantillons
de sommet peu pentus. Trois couronnes et trois cerisiers contrôlés en blocs réels.
- 39 366 densités profondes et aériennes identiques à la base ; comparaison
supplémentaire hors du massif. Aucun niveau Y périodique réintroduit.
- 1 545 échantillons rocheux contre 8 de terre/herbe parmi les fortes pentes
contrôlées. Les plantations trouvent un sol de pente ≤0,75 dans leur chunk.
- Ancres, 49 cartes/cadres, rosaces, galerie, quatre coffres de ruines, donjon,
gemmes, soufre et étangs contrôlés. Cascade large et absence d’arbres dans
les colonnes d’eau et de berge contrôlées conservées.
Démarrage final : 12,126 s à froid et 0,613 s à chaud, zéro région d’hydrologie ;
83,610 s à froid et 18,501 s à chaud avec
l’ensemble des contrôles et le remplissage de l’atlas. Ces contrôles ne tournent
pas au lancement du solo. Les mesures intermédiaires pendant la compilation
concurrente ne servent pas de référence de performance.
`./gradlew check build assemblePack assembleTestPack` réussi en 9 min 9 s,
265 GameTests réussis. Après ajustement du placement des cerisiers et de son
contrôle de réouverture, `:sanctuary-test:check :sanctuary-test:build` réussi et
pack de test réassemblé : 175 classes et 121 ressources vérifiées dans le JAR,
identique à sa copie distribuée (`build/eroded192-pack-receipt.json`).
La validation technique ne vaut pas validation esthétique du créateur. Cette
itération vise le massif central de la graine de visite ; elle ne remodèle pas
les récifs aériens. Pas de publication ni de mise à jour de l’installation Prism.
## Visite
Nouveau solo `Sanctuary-Eroded-Massif-192-Solo`, run `visite192`, profil `eroded`,
graine 42, vue 32 et simulation 12, spectateur et commandes autorisées.
Position préparée (94,316,153), face au massif. Les 49 cartes et cadres ainsi
que les huit ancres éteintes et l’origine sans relais ont été relus dans cette
copie neuve. Options et shader repris du solo 191, fermé et sauvegardé à 22:14.
Client Vulkan lancé et entrée dans le monde confirmée à 22:34 ; vue 32,
simulation 12 et visibilité de l’ascension contrôlées dans
`build/eroded192-solo.log`.
+83
View File
@@ -0,0 +1,83 @@
# STEM-185 — ligne fine, portail de toiture et vitres reliées
Ticket du 30 septembre 2026, branche `codex/fine-stem-beta185`.
Le créateur valide la fleur et le palais beta.184, ainsi que la galerie inférieure.
Il demande de supprimer l'escalier, les paliers et la grosse colonne : une ligne
d'un bloc doit guider visuellement le bateau-poule vers le palais. Compléments
pendant la réalisation : incruster le portail horizontal au sommet du dôme,
libérer l'espace au-dessus de la carte, fermer le jour sous les vitres supérieures.
## Contrat
Nouveau profil de labo `stem`, preset `sanctuary_test:fine_stem_v1`, réglages
`sanctuary_test:fine_stem_v1_10`, graine de visite **42**, version **beta.185**.
La dimension 1600, le champ de bruit 640, l'île et les eaux retenues restent
ceux de beta.184. Aucun changement de format, d'ancien preset ou de sauvegarde.
La visite beta.184 a été arrêtée proprement à la demande du créateur ; une
nouvelle sauvegarde est préparée pour la relance.
## Résultat
- Rosace et Bugrock toujours en (0,640,0), palette et huit axes conservés.
- **Une seule colonne de calcite en (0,Y,0)** au-dessus du dôme inférieur,
de Y=652 jusqu'au départ de l'évasement à 1160. Pas de spirale, de marches,
de plateforme intermédiaire, de balustrade ou de pont d'escalier.
- Les huit nervures s'élargissent progressivement près du sommet, en partant
du même bloc central. Fleur, balcon et pièce du palais à Y=1278 conservés.
- Portail horizontal 7×7, ouverture 5×5, **incrusté à Y=1309 dans le dôme**.
Son cadre remplace les vitres sommitales et touche la toiture sur tout son
pourtour extérieur. Le passage central traverse la voûte ; plus de cadre
suspendu au milieu de la salle, au-dessus des 49 cartes au sol.
- Un soubassement de calcite ferme le bloc d'air sous les panneaux de verre.
Les huit passages restent ouverts. Leur dégagement est vérifié avec les
collisions natives, pour une coque standard de 1,375 bloc et son pilote.
- Les moteurs du bateau-poule existant ne comportent pas de plafond fixe à
640. Aucun changement de mécanique de vol ni de comportement de familier.
La révélation de la couronne en montant reprend beta.184. La galerie inférieure,
son portail 5×5, le soufre, les secteurs miniers, les étangs et le donjon restent
ceux validés. Les portails restent des infrastructures, sans voyage dimensionnel.
## Vérifications et visite
Contrôle natif final `solo185c/stem/42` réussi : **508 tranches d'un seul bloc**,
16 approches libres (huit par lieu, coque et pilote légèrement au-dessus des
tapis de mousse), 104 colonnes vitrées appuyées sur calcite, 24 blocs de cadre
reliés à la toiture. Les 16 868 entrées du plan correspondent aux blocs générés.
La voûte hors de l'ouverture centrale reste identique à beta.184. Aucune marche
ni palier dans cette variante. Reçu : `build/stem185-quick-result.json`.
L'île conserve ses 567 échantillons de densité vérifiés, zéro région d'hydrologie,
les trois cerisiers, cinq spawners, quatre wagonnets à butin, la galerie, le soufre
et les trois secteurs de gemmes. Le serveur démarre en 5,2 s ; préparation avec
sondages, atlas et contrôles en 42,3 s. Ce dernier temps inclut les tests.
Lecture NBT du monde arrêté : 49 cartes complètes et figées, cadres horizontaux
et identifiants uniques. Ancien cadre suspendu en air, nouveau cadre de toiture
en obsidienne, tige centrale isolée et soubassement du vitrage confirmés.
Reçus : `build/stem185-saved-atlas.json`, `build/stem185-saved-blocks.json`.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch`
réussi en **7 min 3 s**, **265/265 GameTests**. Journal :
`build/stem185-check-build.log`. Le daemon de compilation a été arrêté pour
libérer la mémoire avant le client Vulkan.
Solo Vulkan ouvert le 30 septembre à **07:32:51**. Nouveau monde
`visite185/stem/42`, `Sanctuary-Fine-Stem-185-Solo`, créatif, commandes et vol,
vue 32 chunks et simulation 12. Départ préparé dans le palais supérieur.
Entrée confirmée en (6.5,1280,8.5), vue 32 et simulation 12 dans le journal
`build/stem185-solo.log`. Vérification native du frustum réussie à 07:32:53 :
couronne cachée depuis le sol, révélée en arrivant à la rosace. Inspection de
la fenêtre du jeu : carte au sol présente et vitrages reliés au soubassement.
L'ancienne sauvegarde beta.184 reste conservée. Aucun canal public ou instance
Prism modifié ; seuls les artefacts locaux et le laboratoire sont livrés.
Les contrôles de passage ne
remplacent pas un trajet intégral piloté en bateau-poule.
| Lieu | Téléportation |
| --- | --- |
| Rosace du Bugrock | `/tp 0.5 639 5.5 180 -20` |
| Palais et carte au sol | `/tp 6.5 1280 8.5 140 35` |
| Portail dans la toiture | `/tp 0.5 1312 0.5 180 75` |
| Liaison fine, vue extérieure | `/tp 24 920 24 135 -20` |
| Portail inférieur | `/tp 0.5 177 7.5 180 30` |
+53
View File
@@ -0,0 +1,53 @@
# Les quatre îles dans Sanctuary normal
## Validation du 5 octobre 2026
Le joueur valide le rendu beta.224 et demande que les quatre îles soient
disponibles dans Sanctuary de base, sans Sanctuary Test.
Branche de vérification : `codex/four-islands-base224`, base `4554ea1`.
L’audit confirme que cette intégration est déjà effective dans le mod et le
MRpack normal beta.224. Aucun transfert supplémentaire de code n’est nécessaire.
Cette livraison documentaire ne change ni les binaires ni leur version.
| Ancre | Expansion validée | Contenu principal |
| --- | --- | --- |
| Nord | Glaciale | Taïgas géantes, glace, améthyste, igloos et manoir |
| Sud | Aride | Canyons colorés, forêts, sentiers et pyramide piégée |
| Ouest | Océanique | Océan, monument, épaves et berges en roche jaune |
| Est | Volcanique | Volcan actif, jungles, bambou et temple de jungle |
Créer un **nouveau monde Sanctuary**, avec le choix Petit/Moyen/Grand.
Les expansions de 1024 blocs sont débloquées par leurs ancres cardinales
et leurs demandes de matériaux ; elles ne sont pas toutes prégénérées au départ.
Les anciens mondes conservent leur génération enregistrée.
## Contrôle de l’intégration
- Le preset public `sanctuary:sanctuary` utilise `island224_medium`. Le sélecteur
du mod normal propose également les profils Small et Large de cette génération.
- `SanctuaryMod` enregistre directement les générateurs, l’adaptateur d’expansion
et les interactions des ancres. Aucun de ces chemins ne dépend de l’activation
de `QuickTestMod`. Les anciens noms Java et identifiants `sanctuary_test:*`
sont conservés pour la compatibilité ; ils ne constituent pas une dépendance
au module optionnel.
- Vérification du MRpack normal : générateurs, structures et biomes des quatre
directions présents pour les trois tailles ; un seul JAR Sanctuary, aucune
dépendance au module `sanctuary_test`, aucun monde ni JAR Sanctuary Test inclus.
- La création conserve les types vanilla et une seule entrée publique Sanctuary.
- Le build complet et les sept GameTests beta.224 ont déjà réussi, dont le
chargement des profils sans le module de labo. Ils ne sont pas relancés pour
cette modification documentaire. Les essais natifs des différentes îles sont
décrits dans leurs tickets ; cet audit ne revendique pas une nouvelle partie
complète avec les quatre îles simultanément.
Reçu local : `build/four-islands-base224-receipt.json`.
Artefact standard : `build/Sanctuary-beta.224.mrpack`, copie identique dans
`~/Downloads/Sanctuary-beta.224.mrpack`, SHA-256 :
```text
01aed4e6a0d9e2965ed8201372eef3aaecab3b0c6dce3fb84586895ed9076885
```
Cette validation ne migre aucun monde et ne modifie pas le canal packwiz ou
l’installation Prism personnelle.
+101
View File
@@ -0,0 +1,101 @@
# WG-GALLERY-198 — création Large interrompue par la galerie centrale
Branche `codex/gallery-generation-beta198`, depuis beta.197. Minecraft 26.3,
Fabric 0.19.5, Java 25. Retour R013 et journal `message-11.txt` fourni par le
créateur : arrêt Windows à la création Large, graine `4736390610738281858`.
## Cause et correction
L'exception `No supported central gallery floor` dans `Cavern183.create`
interrompt la décoration du premier chunk. Le repli beta.197 exige encore de
la roche exactement en (0,0), sous la surface de cette même colonne. Sur cette
graine, son sommet n'est qu'à Y=168 et presque toute la colonne traverse du
vide, alors que les colonnes voisines possèdent des assises. L'erreur a été
reproduite sur macOS avec la même graine avant modification. Ce journal ne
montre pas une panne du pilote Vulkan ni un manque de mémoire.
Les nouveaux profils beta.198 conservent d'abord toutes les recherches
existantes. Un dernier repli ne s'exécute que lorsqu'elles échouent : il compare
l'assise et la couverture sur l'emprise de la chambre, de Y=32 à Y=276, sans
condition éliminatoire sur la seule colonne centrale. Au plus 12 250 sondes,
une seule planification mise en cache par source de biomes. Même un puits
entièrement vide conserve la salle et sa fondation locale existante, plutôt
que d'annuler la création du monde. Dans ce cas limite, la chambre peut être
ouverte sur le vide : ce correctif ne prétend pas créer une cavité fermée dans
une roche absente.
Le portail reste horizontal en X=0, Z=0. Les dimensions de la chambre,
maçonnerie et règles du relief, de l’eau, des biomes et des minerais restent
identiques.
Aucun calcul régional d'hydrologie ajouté.
## Sauvegardes et distribution
`stable_gallery198` est un paramètre de codec additif, faux par défaut.
Les trois nouveaux profils `shared_island198_{small,medium,large}` et le preset
public Sanctuary l'activent. Les profils 196/197 restent présents et gardent
leur comportement ; leur personnalisation conserve leur révision exacte.
Les protections de spawn introduites en 197 restent actives en 197 et 198.
Le pack de test est destiné à un **nouveau monde**. Une création interrompue
beta.197 ne migre pas automatiquement en beta.198 : recréer un nouveau monde
avec la même graine et la taille souhaitée. Aucun monde personnel modifié,
aucun chunk régénéré, aucune publication du canal ni installation Prism.
## Vérifications
- Échec beta.197 reproduit dans `build/worldgen-lab/gallery198-baseline/`.
- Tests synthétiques réussis : puits vide, appuis autour d'un centre vide,
fine couche haute, roche pleine, déterminisme et borne de calcul.
- Matrice native réussie : Small/Medium/Large, graines 0, 17, 42,
`4736390610738281858` et `-9223372036854775808`. Plans répétés à l'identique ;
toutes les galeries admises par beta.197 conservent exactement leur plan.
Le nouveau repli s'active pour la graine du journal, dans les trois tailles.
- Small, Medium et Large sur la graine fournie : création puis réouverture
réussies. Portail en `(0,183,0)`, trois salles accessibles, respectivement
1 927, 1 925 et 1 930 cellules accessibles ; géométrie et ornements identiques
après reprise. Démarrages serveur à froid : 18,4 / 24,2 / 21,1 secondes ;
ces mesures locales ne sont pas un temps de chargement garanti sous Windows.
- Client intégré **Vulkan**, vue 8 chunks et mémoire Java 2 Gio : Large sur
la graine exacte, arrivée réelle en `(-15.5,254,-15.5)`, huit recherches
natives de spawn sur l’île. Parcours FR/EN des trois tailles, annulation,
aller-retour disque et maintien des révisions historiques 196 et 197.
Réussi en 1 min 2 s, trace `build/gallery198-client.log`.
Commande du contrôle ciblé, rejouable dans un nouveau dossier :
```sh
python3 scripts/worldgen_lab.py verify --profile large \
--seed 4736390610738281858 --run galerie-regression-neuve \
--checks gallery198 --memory 2048
```
Les traces finales sont dans `build/worldgen-lab/gallery198-targeted/`.
Le mode normal `--checks full` conserve toutes ses assertions. Son premier
passage dans `gallery198-fixed/` a démarré correctement puis s'est arrêté sur
un **autre contrôle de laboratoire** : le secteur émeraude contient 171 blocs,
dont 120 exposés, contre le minimum attendu de 200. Ce seuil est uniquement
vérifié par le banc de test, pas pendant une partie ordinaire. Ni l'assertion
ni les minerais ne sont modifiés ici. La vérification complète de toutes les
décorations sur cette graine reste donc ouverte ; seuls les contrôles ciblés
explicitement indiqués sont déclarés réussis.
Aucun essai effectué directement sous Windows ; le défaut du journal est
reproduit avec le même générateur natif et la même graine sur cette machine.
`./gradlew check build assemblePack assembleTestPack -PsanctuaryFocusedTests=menus`
réussi en **4 min 27 s**, 139 tâches : contrôles purs dont le nouveau repli,
quatre GameTests menus et assemblages. Journal : `build/gallery198-check-build.log`.
Le parcours client utilise une instance de développement et ne produit pas de
campagne de captures.
Export local **Sanctuary-Test-beta.198.mrpack**, **12 282 084 octets**.
SHA-256 : `647498a0da3330ce0483e65fe6510ec8d09b6975365261fe59a57d61f3ef0688`.
Archive ZIP, versions, dépendances et classes de chaque JAR vérifiées contre
le build. Toutes les anciennes ressources de données restent identiques à
beta.197, sauf le preset public qui sélectionne maintenant Medium beta.198.
Les nouvelles ressources activent explicitement le correctif ; les anciens
profils ne le font pas. Les tests natifs finaux correspondent à l'empreinte
finale des sources de génération. Reçu : `build/gallery198-artifact.json`.
Copie et guide dans `Downloads/`, sans sauvegarde, réglage personnel ni journal
inclus dans l'archive.
+125
View File
@@ -0,0 +1,125 @@
# ANCHORS-186 — rosaces ornementées et huit refuges
Ticket du 30 septembre 2026, branche `codex/hidden-anchors-beta186`.
Retour sur beta.185 : retirer les barrières supérieures, conserver la silhouette,
ajouter de fins liserés au verre et intégrer huit ancres dans le terrain de leur
secteur de couleur, en surface, en grotte et sur les récifs.
## Contrat
Nouveau laboratoire `anchors`, preset `sanctuary_test:hidden_anchors_v1`,
graine de visite 42, beta.186. Génération déterministe, recherche bornée dans
le champ de densité existant et écritures limitées au chunk en décoration.
Aucune régénération des visites précédentes ni modification des anciens presets.
Les huit couleurs reprennent la palette du Bugrock, dans le même ordre
que les rosaces. Les ancres conservent le bloc et ses propriétés existantes.
Les dépôts distincts restent locaux à ce prototype : ils allument l'ancre et
sa gemme sur le Bugrock ; ils ne génèrent pas encore d'expansion. Les coûts
sont des matériaux accessibles sur l'île, sans or ni redstone.
## Réalisation
Le balcon supérieur perd ses murets. Deux liserés alternent calcite et cuivre
patiné sur chaque dôme, en remplaçant une mince bande de verre. Huit petits
losanges ponctuent les grandes verrières. Le volume, les couleurs dominantes,
la tige d'un bloc, le Bugrock à Y=640, le portail de toiture et l'atlas restent
ceux de beta.185. Les passages sur les huit axes restent dégagés.
La recherche échantillonne une grille finie et les grands récifs existants.
Elle exige une base rocheuse et un débouché naturel praticable. Deux secteurs
aériens sont retenus lorsqu'ils disposent de récifs compatibles ; les autres
privilégient alternativement une grotte ou la surface, avec repli sur un autre
emplacement naturel admissible du même secteur. Le choix varie avec la graine.
Le manque de site sûr fait échouer ce laboratoire explicitement plutôt que de
fabriquer une ancre au-dessus du vide. Seule la graine de visite est certifiée.
Les refuges sont de petites poches irrégulières : sol légèrement ondulé,
reliefs dans la roche présente, accès court décalé, crêtes érodées, mousse,
azalées et verre de couleur au piédestal. Certains reliefs cachent une source
de lumière, d'autres restent sombres. Les réservations évitent la galerie,
le donjon, le soufre et les bassins connus. Elles empêchent aussi la décoration
d'un chunk voisin de reboucher les volumes, sans bloquer les actions des joueurs.
Aucun calcul d'hydrologie régionale ni recherche par tick n'est ajouté.
| Secteur | Couleur | Dépôt en main |
| --- | --- | --- |
| Nord | Bleu clair | 32 pierres |
| Nord-est | Vert clair | 16 bûches de chêne |
| Est | Vert | 16 blés |
| Sud-est | Orange | 16 lingots de cuivre |
| Sud | Rouge | 16 charbons |
| Sud-ouest | Magenta | 8 éclats d'améthyste |
| Ouest | Jaune | 8 lingots de fer |
| Nord-ouest | Cyan | 16 verres |
Clic droit sur l'ancre : le serveur valide le site, le matériau et la quantité.
Un dépôt exact allume l'ancre et le bit de couleur associé au Bugrock. Les
états restent dans les propriétés natives des blocs ; aucune nouvelle base de
progression ou migration. Les textes FR/EN existants sont réutilisés. Le
profil 173 et ses anciens coûts ne sont pas modifiés.
## Vérification
Premier contrôle natif réussi sur `solo186b/anchors/42` : huit ancres, deux
récifs aériens, deux grottes et quatre surfaces/flancs. Plan déterministe de
8 650 entrées dans 26 chunks, calculé en 2,3 s. Huit dépôts vérifiés dans un
ordre non séquentiel ; tous les bits sont indépendants, les mauvais dépôts et
les répétitions conservent les objets. Les états initiaux sont restaurés après
ce test, avant la sauvegarde de visite.
Palais : 144 murets retirés, 384 blocs de liserés/losanges incrustés,
4 944 blocs de verre conservés, seize approches libres. Le volume et le cadre
du portail restent inchangés. Les huit teintes existent dans les deux rosaces.
La première réouverture a révélé un ancien contrôle de cerisiers basé sur un
compteur de génération en mémoire. Le contrôle lit désormais les troncs déjà
sauvegardés lorsqu'il n'y a pas de compteur ; aucun arbre n'est régénéré.
Validation finale sur `solo186c/anchors/42` réussie à froid puis après
réouverture : 567 échantillons de densité conservés et zéro région d'hydrologie.
Démarrage serveur 6,9 s à froid / 0,66 s à chaud ; prêt avec l'ensemble des
sondages et contrôles en 44,7 s / 6,4 s. Le plan des huit refuges prend 2,28 s
à froid. Ces mesures incluent du travail de vérification et ne constituent pas
une promesse de temps de chargement du client.
Lecture de la sauvegarde arrêtée : huit ancres de secteurs 0 à 7, éteintes,
Bugrock allumé avec masque de relais nul ; 49 cartes sauvegardées, complètes,
figées, et cadres horizontaux uniques. Aucun dépôt de contrôle ne reste activé
sur le monde proposé au créateur.
Reçus ignorés : `build/anchors186-quick-result.json`,
`build/anchors186-warm-result.json`, `build/anchors186-saved-blocks.json`,
`build/anchors186-saved-atlas.json`.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch`
réussi en **6 min 49 s**, **265/265 GameTests**. Journal
`build/anchors186-check-build.log`. Le daemon de compilation a été arrêté avant
le client pour libérer la mémoire. Solo Vulkan ouvert le 30 septembre à **08:08:19**, vue 32 et simulation 12
confirmées dans `build/anchors186-solo.log`. Contrôle de visibilité de la couronne
réussi à 08:08:20. La fenêtre du jeu confirme le balcon sans murets et les
vitrages reliés au soubassement. La visite est laissée au créateur sans téléportations d’inspection supplémentaires. L'aspect des huit
refuges reste à apprécier ensemble en jeu. Aucun canal public ni instance
Prism n'a été modifié.
## Visite — graine 42
Solo neuf `visite186/anchors/42`, `Sanctuary-Hidden-Anchors-186-Solo`,
vue 32 chunks, simulation 12, créatif, vol et commandes ; départ dans le
palais supérieur. Sauvegarde beta.185 conservée. Les emplacements suivants
sont des raccourcis de test, pas des marqueurs visibles dans le jeu.
| Secteur | Milieu | Lumière du refuge | Accès de visite |
| --- | --- | --- | --- |
| Nord | Surface / flanc | Lumineux | `/tp -71.5 243 -226.5 0 0` |
| Nord-est | Surface / flanc | Sombre | `/tp 96.5 186 -82.5 0 0` |
| Est | Récif aérien | Lumineux | `/tp 213.5 444 21.5 180 0` |
| Sud-est | Surface / flanc | Sombre | `/tp 156.5 161 193.5 0 0` |
| Sud | Grotte | Lumineux | `/tp -83.5 115 215.5 180 0` |
| Sud-ouest | Surface / flanc | Sombre | `/tp -107.5 252 181.5 0 0` |
| Ouest | Grotte | Lumineux | `/tp -96.5 223 24.5 90 0` |
| Nord-ouest | Récif aérien | Sombre | `/tp -102.5 404 -171.5 90 0` |
Palais : `/tp 6.5 1280 8.5 140 -15` ; Bugrock : `/tp 0.5 639 5.5 180 -20`.
+128
View File
@@ -0,0 +1,128 @@
# DISCOVERY-183 — lieux et ressources de Sanctuary Island
Ticket du 30 septembre 2026, branche `codex/island-discovery-beta183`.
Le créateur a visité le solo beta.182 et valide la palette naturelle, la rosace,
les étangs et la génération sous l'île. Il demande un portail **horizontal**,
les secteurs miniers et le soufre manquants, l'ISS séparée et un exemple d'eau
haute qui suit le dénivelé. Son complément relie les vitres de la rosace aux
huit couleurs du Bugrock et à une géographie lisible, froide au nord, chaude au sud.
## Contrat
Nouveau preset facultatif `sanctuary_test:discovery_v1`, profil `discovery`.
Graine de visite : **42**. Anciens presets, sauvegardes et chunks conservés.
La source de biomes possède une option `discovery` absente/false pour les
anciens profils : seule la nouvelle génération active la poche de soufre.
Aucune migration, expansion, activation de portail ou progression ajoutée.
Minecraft 26.3, blocs de soufre natifs et minerais Sanctuary existants.
## Contenu
- Galerie centrale agrandie, toujours taillée dans la roche, avec ses deux
annexes et passages en boucle. Cadre d'obsidienne de **5 × 5**, trou central
de **3 × 3**, fond un bloc plus bas, sec. Le gardien viendra ultérieurement.
- Rosace : positions, nervures, passages et Bugrock à Y=320 conservés.
Seules les vitres changent. Ordre du dessin source, depuis le nord :
bleu clair, vert clair, vert, orange, rouge, magenta, jaune, cyan.
Le petit sommet blanc conserve le rappel du logo central blanc.
Cette rose colorée donne une convention géographique ; elle ne transforme
pas encore les biomes de l'île en huit régions ni n'allume les relais.
- Trois secteurs de gemmes : saphir au nord (0,-176), émeraude à l'est
(176,0), rubis au sud (0,176), chacun de rayon 64 blocs autour des centres
de chunks. Petits amas sur les faces de grotte, entre Y=40 et 287,
toujours au moins 13 blocs sous la surface, au plus douze blocs par chunk
retenu. Les blocs exposés et stocks sont comptés dans
le monde effectivement généré. Diamants, cuivre, charbon, fer et lapis
gardent leur distribution précédente ; aucun or ni redstone ajouté.
- Une caverne de soufre au sud-ouest, altitude choisie dans la roche,
soufre/cinabre/calcite, ouverture vers le jour et trois formations de soufre
enracinées à la surface pour la repérer. Pas de lave ni de nouveau mob.
- Un lac supérieur supplémentaire et son bassin aval, reliés par un chenal
en marches sur quatre blocs de dénivelé. La partie aval s'ouvre au jour.
Les deux systèmes d'étangs beta.180 restent présents. Recherche locale
bornée et plan mémorisé ; aucune hydrologie régionale calculée.
- ISS entre Y=575 et 591 : trois modules métalliques reliés et praticables,
quatre ailes solaires, poutre centrale, antenne, porche d'arrivée et
observation vitrée vers l'île. Architecture originale, sans schematic
externe. La salle nord contient une table de cartes dans des cadres lumineux
horizontaux. Le rayon du générateur détermine la mosaïque et la salle :
5 × 5 pour le petit format (512), 7 × 7 pour le moyen (724), 9 × 9 pour le
grand (1024). Ce profil de terrain reste au format moyen ; les autres
dimensions de station sont vérifiées géométriquement, sans ajouter de
nouveaux profils de terrain à cette livraison. Aucun familier spécial,
quête ou portail vers les hauteurs fonctionnel ajouté.
Toutes les nouvelles écritures appartiennent au chunk en cours de décoration.
Plans locaux calculés une fois, aucune reconstruction dans une sauvegarde
ouverte. Les cartes sont des objets Minecraft natifs, persistés avec leurs
cadres. Une file finie les prépare par tranches de quatre lignes avec un budget
cible de 3 ms par tick. Projection topographique de la graine au pas de quatre
blocs, palette réelle pour les chunks déjà chargés, biomes pour les autres :
c'est une vue d'ensemble du terrain initial, pas une photographie détaillée
de toutes les constructions. Aucun chargement de chunks éloignés demandé pour
la carte. Les cartes terminées sont figées comme une trace de l'ancienne
expédition, et ne sont ni recréées ni regagnées si un joueur retire un cadre.
Une interruption reprend une carte inachevée avec son identifiant existant.
## Vérifications et visite
Monde neuf final `solo183e/discovery/42`, serveur arrêté et sauvegardé proprement :
567 échantillons de densité conservés sous Y=216, zéro région d'hydrologie,
trois cerisiers, les deux bassins antérieurs et les cinq spawners/quatre caches
conservés. Galerie : 1 939 surfaces reliées sur 1 979 colonnes, cadre 5 × 5 et
fosse sèche 3 × 3 vérifiés. Rosace : géométrie inchangée, huit couleurs présentes
et huit approches libres.
Stocks réellement comptés dans les trois districts : 235 saphirs (176 exposés),
624 émeraudes (441 exposées), 576 rubis (402 exposés). Nouveau système d'eau :
4 311 blocs d'eau reliés et débouché extérieur vérifié. La ventilation du soufre
est ouverte jusqu'au terrain local du débouché, plutôt qu'à la hauteur plus
basse du centre de la poche.
ISS : 4 742 entrées de plan, trois modules reliés, quatre ailes solaires,
49 cartes distinctes et supportées dans 49 cadres horizontaux. Les géométries
5 × 5, 7 × 7 et 9 × 9 couvrent les rayons 288, 395 et 544 avec leurs marges de
terrain. La mosaïque courante couvre 896 × 896 blocs. Calcul de son aperçu :
2 039 ms au total ; aucun chargement de chunk distant dans ce calcul. Lecture
NBT après arrêt : 49 cartes pleines et figées, 49 identifiants uniques, tous
les cadres orientés vers le haut, centres jointifs et aucun marqueur de travail
inachevé. Assemblage des pixels sauvegardés inspecté visuellement ; il ne s'agit
pas d'une capture du jeu. Rapport local `build/discovery183-saved-atlas.json`.
Démarrage serveur mesuré à 4,4 s ; préparation avec sondages, génération des
zones visitées et contrôles terminée à 41,1 s. Ce dernier chiffre inclut les
tests synchrones, ce n'est pas un temps de démarrage normal du solo.
Rapport `build/discovery183-quick-result.json`.
`./gradlew check build assemblePack assembleTestPack` réussi en 7 min 20 s,
**265/265 GameTests** (`build/discovery183-check-build.log`). Après les deux
retouches finales limitées au laboratoire (ventilation et lecture des couleurs
réelles de la carte), compilation, contrôles du mod de labo, assemblages et
export du lanceur ont été refaits ; les checks des trois modules inchangés,
déjà réussis, n'ont pas été répétés dans cet assemblage final. Journal
`build/discovery183-final-assembly.log`. Le monde `solo183e` vérifie ce code final.
Solo neuf `visite183/discovery/42`, `Sanctuary-Discovery-183-Solo`, vue 32,
simulation 12, créatif, vol et commandes. Départ préparé devant la table de
l'ISS. Entrée en jeu confirmée dans le journal le 30 septembre à 03:11:11 :
KokaLab en (4.5,580,-12.5), vue 32. Passage en spectateur à 03:11:48.
Client Vulkan actif.
Aucune sauvegarde antérieure ni instance Prism modifiée.
| Lieu | Téléportation de visite |
| --- | --- |
| Salle des cartes ISS | `/tp 4.5 580 -12.5 140 35` |
| Porche ISS | `/tp 0.5 577 28.5 180 0` |
| Rosace | `/tp 0.5 319 5.5 180 0` |
| Portail inférieur | `/tp 0.5 177 7.5 180 30` |
| Poche de soufre | `/tp -152 180 152` |
| Indice de soufre en surface | `/tp -158 281 149` |
| Bassin supérieur | `/tp -96 254 -192` |
| Saphirs | `/tp -62 236 -204` |
| Émeraudes | `/tp 114 172 -30` |
| Rubis | `/tp -60 192 146` |
Graine 42 testée en génération native ; les autres graines restent à éprouver.
Palette, volumes, positionnement des cartes et proportions de l'ISS à valider
en visite. Les cartes sont une vue d'ensemble figée de l'île principale,
pas encore un atlas vivant des expansions.
+78
View File
@@ -0,0 +1,78 @@
# DETAILS-188 — fonds d'étangs, soufre vivant et palettes des ancres
Ticket du 30 septembre 2026, branche `codex/living-details-beta188`.
Le créateur valide l'orientation des ancres et les formes des bassins beta.187.
Il demande des refuges adaptés au milieu et à la couleur, des fonds sédimentaires
végétalisés sans arbres dans l'eau, et les pics/geysers du biome de soufre.
Nouveau profil `details`, preset `sanctuary_test:living_details_v1`, graine 42.
Aucune modification des anciennes sauvegardes ou générations. Même densité,
mêmes bassins et mêmes emplacements/orientations d'ancres que beta.187.
Livraison locale de laboratoire ; objectif de visite avant 9 h.
## Réalisation
Géométrie et orientation des refuges conservées. Terre, herbe et terre stérile
pour la surface ; tuff, deepslate et calcite sous roche ; calcite et diorite
sur les récifs. Les incrustations reprennent la teinte du secteur. Le verre
reste au-dessus de l'améthyste, du côté de l'expansion.
Les bassins sont remplis avant les arbres. Leur lit existant reçoit des plages
cohérentes d'argile, boue, sable et gravier, sans agrandissement ni coque ajoutée.
Les colonnes de plantation immergées sont réservées pendant la décoration.
Herbes marines et quelques touffes de kelp occupent les fonds ; les matériaux
meubles exigent un support rocheux. Contours et niveaux restent ceux de 187.
Le soufre reçoit des stalagmites et stalactites natives, avec des longueurs
variables, et des sources périodiques : magma, soufre puissant, eau source.
Les volumes humides réservés, le donjon et les refuges sont évités. Les entités
de bloc sont explicitement créées et sauvegardées pour activer les minuteries
natives des geysers. Le contrôle vérifie l'entité et le ticker après réouverture.
Table de butin propre à ce nouveau preset : une ou deux pièces en fer par
wagonnet, parmi quatre armures, épée, pioche, hache et pelle. Enchantement par
la fonction native, puissance de table 12 à 20, sans enchantement trésor.
Les gemmes et les ressources déjà présentes restent dans le butin. Les anciens
wagonnets et tables ne changent pas. La progression du futur monde minéral
reste une intention, hors de cette livraison.
## Vérifications
Premier monde : les huit refuges gardent exactement leurs positions et axes.
Quatre sédiments, 611 colonnes végétalisées et zéro tronc dans les bassins.
Plan de 496 spires et 39 geysers ; 138 blocs de pic et huit sources contrôlés.
32 tirages de butin : toujours une ou deux pièces enchantées en fer, les huit
types d'équipement observés. Génération finale `solo188c/details/42` puis réouverture réussies, avec contrôle
des entités de geyser et de leurs tickers natifs. Les blocs et entités sont
relus dans la sauvegarde arrêtée : huit ancres éteintes, Bugrock allumé sans
relais, 49 cartes complètes et 49 cadres horizontaux. Les quatre wagonnets sauvegardés portent tous la nouvelle table
`sanctuary_test:chests/mine_cache_188` ; reçu `build/details188-saved-loot.json`.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch`
réussi en 7 min 54 s : 265 GameTests réussis. Les contrôles natifs finaux passent
après la correction des entités de geyser, à froid et après réouverture.
Le JAR du labo a ensuite été reconstruit et le pack optionnel resynchronisé
avec `scripts/test_pack.py` : ses 146 classes correspondent aux classes compilées,
sa table de butin correspond à la source et le JAR distribué est identique.
Lors des 32 tirages après réouverture, 51 pièces enchantées couvrent les huit
types d'équipement. Reçu de la suite générale : `build/details188-check-build.log`.
Solo `visite188c/details/42`, monde `Sanctuary-Living-Details-188-Solo`, ouvert
sous Vulkan : connexion à 09:00:41, vue 32 et simulation 12 confirmées dans le
journal, puis passage du joueur en spectateur à 09:00:58. L'objectif avant 9 h
a donc été dépassé. Le contrôle visuel des décors et des éruptions reste à faire
pendant la visite ; la présence des blocs, entités et tickers est vérifiée.
## Raccourcis de visite
- Bassin ouest : `/tp -104.5 269 119.5 180 35`
- Soufre et geysers : `/tp -217.5 159 -16.5`
- Autre source : `/tp -201.5 150 8.5`
- Wagonnet du donjon : `/tp 45.5 144 60.5`
- Ancre nord : `/tp 36.5 250 -168.5 180 0`
- Ancre sud, grotte : `/tp -71.5 176 205.5 0 0`
- Ancre est, récif : `/tp 214.5 444 16.5 -90 0`
Nouveau solo uniquement, vue 32, simulation 12, créatif avec vol et commandes.
Aucune publication du canal public ni modification de Prism.
Mesures du labo final : démarrage 12.839 s à froid / 0.912 s après réouverture ; prêt avec tous les contrôles en 71.525 s / 14.114 s. Mesurées pendant la suite générale, hors chargement graphique. Zéro région d’hydrologie. Reçus ignorés `build/details188-final-cold-result.json` et `build/details188-final-warm-result.json`.
+50
View File
@@ -0,0 +1,50 @@
# UI-194 — retirer Amis du menu principal
Branche `codex/main-menu-beta194`, depuis beta.193, Minecraft 26.3.
Le créateur suspend les retouches du terrain et les tests de screenshots,
puis reprend le cadrage des interfaces. Le retrait d’Amis est la première
modification demandée, déjà prévue dans [Storyquest](storyquest-beta173.md).
## Résultat
Le menu principal propose Solo, Multijoueur, puis Options et Quitter sur une
même ligne. Cette dernière suit Multijoueur avec l’espacement natif de 24 unités
GUI. Le bouton Amis n’est plus créé à la place de Realms ; l’entrée Realms et
la petite icône sociale restent retirées. Les commandes restantes gardent
leur ordre clavier et la version Sanctuary reste affichée.
Le parcours de démonstration, dépourvu de Multijoueur, conserve sa disposition
antérieure. Les autres accès sociaux et paramètres du compte ne sont pas
modifiés. Aucun nouveau libellé : les commandes natives restent traduites FR/EN,
les anciennes clés `sanctuary.menu.friends` sont conservées pour compatibilité.
Le menu pause, Habitant, Combat, Factions et Storyquest restent des suites
à concevoir. Aucune source de génération, donnée de biome ou sauvegarde n’est
modifiée par ce lot. Aucune nouvelle série de captures n’est lancée.
## Vérifications
Le parcours natif existant `Title045ClientChecks` est actualisé pour vérifier
l’absence d’Amis et de Realms, la disposition sans ligne vide, l’ordre clavier
et l’ouverture d’Options en FR/EN aux quatre réglages GUI. Ses captures et son
ancien parcours vers la liste d’amis sont retirés.
Validation réussie : `./gradlew check build assemblePack assembleTestPack
:sanctuary:runClientGameTest -PsanctuaryFocusedTests=menus
-PsanctuaryClientTests=true -PsanctuaryTitleClientTests=true
-PsanctuaryClientGraphicsBackend=vulkan`.
Journal : `build/menu194-check-build.log`. Les contrôles purs et les quatre
GameTests serveur ciblés passent. Le parcours client Vulkan passe en FR/EN,
sans capture, avec ordre clavier, absence des boutons retirés et ouverture
d’Options vérifiés. Dans la fenêtre 854 × 480 du test, les réglages GUI 3 et 4
sont plafonnés par Minecraft à l’échelle effective 2.
Les packs normal et de test sont assemblés. La comparaison des JAR beta.193 et
beta.194 confirme que seule `TitleMenuMixin.class` change dans le code livré ;
les données de génération sont identiques. Le module Demeure embarqué ne change
que de version dans ses métadonnées. Reçu : `build/menu194-artifact.json`.
Le labo beta.193 déjà ouvert n’est ni arrêté ni mis à jour par cette livraison.
Livraison locale uniquement ; publication et mise à jour du jeu personnel
ne sont pas demandées.
+115
View File
@@ -0,0 +1,115 @@
# ASCENT-184 — rosace à 640 et palais des hauteurs
Ticket du 30 septembre 2026, branche `codex/natural-ascent-beta184`.
Le retour sur beta.183 rejette l'ISS métallique visible depuis le sol et les
nouveaux bassins supérieurs ovales en marches. La direction retenue est une
machine naturelle : rosace, longue tige parcourable, couronne de palais comme
un parapluie, carte au sol et portail horizontal au-dessus. Dernière correction
explicite du créateur : **la rosace est à Y=640**, pas à 320.
## Contrat de génération
Nouveau profil de laboratoire `ascent`, preset `sanctuary_test:ascent_v1`,
réglages `sanctuary_test:ascent_v1_10`, graine de visite **42**. Nouvelle dimension
`sanctuary_test:ascent_1600`, constructible de Y=0 à 1599. Minecraft 26.3 accepte
ce type de dimension dans la génération native vérifiée. Le bruit du terrain
reste calculé entre 0 et 639 ; la décoration écrit les structures plus haut
dans les sections du nouveau monde. Aucun bruit supplémentaire dans le ciel
vide, aucune hydrologie régionale, aucun changement des sauvegardes précédentes.
Les presets 180–183 restent distincts. Le nouveau profil reprend l'île, ses
minerais, biomes, cavernes, soufre et donjon, mais ne place ni l'ISS métallique
ni les bassins `Water183`. Les étangs souterrains beta.180 précédemment validés
restent présents. Pas d'expansion, migration, nouveau mob ou portail fonctionnel.
## Construction et découverte
- Rosace et Bugrock translatés à **(0,640,0)**, sol à 638. Les huit couleurs et
approches de la rosace sont conservées ; la sortie est rejoint l'escalier.
- Tige de tuf, deepslate, calcite et mousse, nervures enroulées, haltes latérales.
Escalier continu avec marches natives, de 638 à 1278 : 1 923 positions de
parcours, environ 1,9 km de chemin pour 640 blocs gagnés. Largeur généralement
de trois blocs, resserrée aux virages. Le parcours depuis l'île jusqu'à la
rosace reste à concevoir ; le test permet le vol et le spectateur.
- Palais : nervures déployées à partir de 1160, sol à **1278**, voûte à **1310**.
Huit pétales vitrés, passages minéraux, cuivre oxydé, balcons. Pas de panneaux
solaires ni de modules métalliques. Le Bugrock reste uniquement sur la rosace.
- Atlas natif au sol, 49 cartes sur ce terrain moyen, dans des cadres horizontaux.
Dimensions 5×5, 7×7 et 9×9 pour les rayons déjà pris en charge. Identifiants et
marqueurs propres à ce nouvel atlas ; l'atlas 183 reste inchangé.
- Portail supérieur : cadre horizontal 7×7 d'obsidienne, coins en obsidienne
pleureuse, vide central 5×5, à 1287 au-dessus des cartes. Le portail inférieur
conserve son cadre 5×5 et son creux 3×3 à Y=175. Ce sont des infrastructures.
À 32 chunks, la caméra native peut garder un plan lointain de 2 048 blocs :
la hauteur seule ne suffit pas à dissimuler la couronne. Dans cette dimension
uniquement, le frustum refuse les volumes entièrement au-dessus de 1152 lorsque
la caméra est sous 560. La couronne devient donc éligible à l'affichage pendant
l'approche de la rosace ; les règles normales de visibilité restent applicables.
C'est une révélation côté rendu, pas une génération conditionnelle à un joueur.
Un contrôle à l'entrée du client teste les deux API natives de frustum, depuis
le sol et depuis 640. La couronne est aussi au-delà du volume maximal des ombres
Sanctuary depuis le plateau (distance 256, extrusion solaire comprise). Cela
ne supprime pas l'éclairage Minecraft inhérent aux blocs placés dans une colonne.
## Eau dans les creux existants
Recherche locale et bornée dans le champ réel de densité. Chaque candidat est
rempli par parcours des cellules d'air adjacentes sous un niveau horizontal ;
un chemin sortant du volume de recherche, vers le vide ou une zone réservée
fait rejeter le candidat. On monte le niveau par essais bornés tant que la roche
retient l'eau. Aucun mur de retenue, fond d'argile artificiel, marche ou excavation
n'est dessiné. Seules les cellules encore en air reçoivent de l'eau à la décoration.
Les cavités existantes, roches saillantes et végétaux conservés dictent le contour.
Première génération native `solo184a`, graine 42 : 45 essais, plan en 852 ms,
10 402 blocs d'eau dans la grande poche (surface de 1 045 cellules à Y=234),
739 blocs dans la seconde (290 cellules à Y=242). Aucun débouché latéral/inférieur
non retenu détecté après la décoration. Ce sont des eaux retenues ; aucune
simulation de bassin versant ou de rivière à longue distance n'est introduite.
## Vérification et visite
Premier contrôle natif réussi : 567 échantillons profonds identiques, zéro région
d'hydrologie, trois cerisiers, cinq spawners, quatre caches à butin, galerie,
soufre et trois secteurs de gemmes présents. Les 56 246 entrées du plan du palais
correspondent aux blocs générés ; toutes les positions de montée ont un support
et deux blocs libres. Les 49 cartes sont uniques, remplies, figées et supportées.
Serveur démarré en 5,3 s ; prêt en 43,6 s avec génération des sondages et contrôles.
Ce dernier temps inclut les tests et ne mesure pas un démarrage normal du solo.
Validation finale : `./gradlew check build assemblePack assembleTestPack
:sanctuary-test:exportDuoLaunch` réussi en 6 min 54 s, **265/265 GameTests**.
Journal `build/ascent184-check-build.log`. Nouveau monde final `solo184b/ascent/42`
contrôlé et arrêté proprement : serveur en 5,25 s, prêt avec contrôles en 41,63 s ;
plan d'eau en 806 ms, 10 401 et 739 blocs d'eau retenus sans fuite. Le nombre de blocs d'eau diffère d'une cellule entre les deux essais ;
les niveaux et surfaces des plans restent identiques.
Rapport `build/ascent184-quick-result-final.json`.
Lecture NBT du monde arrêté : 49 cartes complètes, figées, identifiants uniques,
49 cadres orientés vers le haut à Y=1279. Air confirmé aux anciens centres
(0,320,0) et (0,576,0), bloc originel à (0,640,0), plancher d'atlas en calcite
et portail supérieur creux. Reçus `build/ascent184-saved-atlas-final.json` et
`build/ascent184-saved-blocks-final.json`.
Solo neuf `visite184/ascent/42`, `Sanctuary-Ascent-184-Solo`, commandes, créatif,
vol, vue 32 et simulation 12. Entrée client Vulkan confirmée le 30 septembre,
contrôle natif du frustum réussi à **03:45:07** : couronne cachée à Y=250,
rosace visible et couronne révélée à Y=640. Journal `build/ascent184-solo.log`.
Le profil local KokaLab de ce monde utilise la couleur Ciel et le familier de
labo par défaut. Le daemon de compilation a été arrêté pour libérer la mémoire.
Aucune sauvegarde antérieure ni instance Prism modifiée. Les archives locales
sont assemblées ; aucun canal public n'est avancé.
| Lieu | Téléportation de visite |
| --- | --- |
| Rosace et départ de la montée | `/tp 0.5 639 5.5 180 -20` |
| Palais et carte au sol | `/tp 6.5 1280 8.5 140 35` |
| Vue extérieure de la couronne | `/tp 45 1295 45 135 10` |
| Grande cavité en eau | `/tp -144 236 -96` |
| Seconde cavité en eau | `/tp -16 245 128` |
| Portail inférieur | `/tp 0.5 177 7.5 180 30` |
Cette première silhouette reste à évaluer en visite, notamment le rythme de
l'ascension et les proportions du palais. La graine 42 est la référence vérifiée ;
la disponibilité de grandes cavités sur d'autres graines reste à éprouver.
+100
View File
@@ -0,0 +1,100 @@
# CAVES-187 — soufre naturel, ancres orientées et bassins visibles
Ticket du 30 septembre 2026, branche `codex/natural-caves-beta187`.
Retour beta.186 : coque de soufre artificielle, pylônes mal orientés et verre
latéral, bassins de surface invisibles. Le relief et les trois secteurs de
gemmes sont appréciés et conservés.
Nouveau profil `natural`, preset `sanctuary_test:natural_caves_v1`, graine 42.
Les anciens presets et sauvegardes restent inchangés. Le laboratoire ajoute
un climat de soufre en trois dimensions dans la roche existante, une approche
en mousse tournée vers le centre pour chaque ancre et des pylônes opposés,
vers l'expansion, portant le verre au-dessus de l'améthyste. L'eau de surface
est recherchée dans des dépressions réellement ouvertes au ciel ; toute fuite
vers le vide fait rejeter le bassin. Aucun calcul régional d'hydrologie.
Le climat de soufre utilise un bruit volumique et respecte la priorité des
marais humides. La palette forme des dépôts cohérents de soufre, cinabre et
calcite dans les blocs rocheux existants. Musique et couleurs du biome natif
26.3 sont conservées. Les carvers, minerais et structures vanilla ne sont pas
importés : l'île conserve ses cavités et sa distribution de ressources.
L'ancienne coque et ses cheminées ne sont plus placées dans ce preset.
Les pylônes portent améthyste puis verre, sur la même verticale. Leur porte
pointe vers la direction exacte du secteur, y compris les diagonales. Le
chemin en mousse est du côté opposé. La sélection vérifie le support naturel
de la porte et du chemin ; les huit emplacements changent pour respecter
cette orientation. La galerie, les rosaces et le palais restent conservés.
L'eau de surface monte dans un creux par parcours prioritaire : chaque voxel
est échantillonné une fois à la hauteur minimale qui le rend accessible.
Une fuite, une structure réservée ou la limite de recherche arrête la montée.
Les surfaces retenues doivent être majoritairement ouvertes au ciel. Aucun
fond ajouté ni découpage elliptique ; les arbres voisins ne peuvent reboucher
les cellules d'eau réservées. Les étangs souterrains appréciés sont conservés.
L'atlas projette aussi les nouvelles eaux et perd le faux repère jaune de la
cheminée supprimée. Les recherches sont bornées, en génération uniquement.
## Contrôles natifs
Graine 42, `solo187e/natural/42` : génération à froid réussie. Recherche des
bassins en 2,674 s, contre 21,546 s au premier essai ; mêmes trois positions,
niveaux et volumes retenus. Démarrage serveur 9,881 s, prêt après l'ensemble
des contrôles en 50,190 s. Ces durées ne mesurent pas le démarrage graphique.
Zéro région d'hydrologie et 567 échantillons de densité profonde conservés.
| Bassin | Niveau | Surface totale | Surface sous ciel ouvert | Blocs d'eau |
| --- | --- | --- | --- | --- |
| Ouest, près de (-104, 88) | 248 | 1 994 | 1 475 | 11 935 |
| Nord-est, près de (120, -136) | 244 | 839 | 536 | 2 329 |
| Sud, près de (8, 136) | 254 | 1 321 | 904 | 9 446 |
Aucune fuite native détectée. Quatre points de visite confirment le biome
sulfureux, de la roche minéralisée et des cavités déjà présentes dans la densité.
Les huit refuges passent le contrôle d'orientation et de verre vertical.
Les dépôts distincts activent les huit gemmes ; les tests restaurent ensuite
les ancres éteintes et le Bugrock allumé sans relais. Les secteurs de gemmes,
les cinq spawners et quatre wagonnets à butin restent vérifiés.
Réouverture réussie : démarrage serveur 0,618 s, prêt avec vérifications en
8,226 s. Les huit ancres sont relues dans la sauvegarde éteintes et le masque
du Bugrock vaut zéro ; 49 cartes complètes, figées, avec 49 cadres horizontaux
uniques. Reçus ignorés : `build/natural187-final-cold-result.json`,
`build/natural187-final-warm-result.json`, `build/natural187-saved-blocks.json`,
`build/natural187-saved-atlas.json`.
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch`
réussi en **7 min 10 s**, **265/265 GameTests**. Journal :
`build/natural187-check-build.log`. Daemon Gradle arrêté avant le client.
Solo Vulkan rejoint à **08:40:37**, départ (-104,5 ; 269 ; 119,5), vue 32
et simulation 12 confirmées dans `build/natural187-solo.log`. Contrôle client
de visibilité verticale réussi à 08:40:39. Le créateur a pris la main et est
passé en spectateur ; aucune téléportation d'inspection supplémentaire.
L'appréciation visuelle des nouveaux bassins et du soufre reste celle de
cette visite ; les mesures ci-dessus sont des vérifications natives.
Seule la graine de visite est certifiée ; pas de migration des anciennes
sauvegardes ni de modification du canal public ou de Prism.
## Visite — graine 42
Nouveau solo `visite187/natural/42`, `Sanctuary-Natural-Caves-187-Solo`.
Vue 32, simulation 12, créatif, vol et commandes. Départ au-dessus du bassin
ouest ; les anciennes visites restent conservées.
| Lieu | Raccourci de visite |
| --- | --- |
| Bassin ouest | `/tp -104.5 269 119.5 180 35` |
| Bassin nord-est | `/tp 120.5 258 -116.5 180 35` |
| Bassin sud | `/tp 8.5 270 156.5 180 35` |
| Soufre, cavité haute | `/tp -215.5 219 -35.5` |
| Soufre, cavité profonde | `/tp -203.5 150 -11.5` |
| Soufre, cavité nord-ouest | `/tp -191.5 152 -179.5` |
| Ancre nord, approche intérieure | `/tp 36.5 250 -168.5 180 0` |
| Ancre nord-est | `/tp 193.5 251 -84.5 -135 0` |
| Ancre est, récif | `/tp 214.5 444 16.5 -90 0` |
| Ancre sud-est | `/tp 157.5 226 145.5 -45 0` |
| Ancre sud, grotte | `/tp -71.5 176 205.5 0 0` |
| Ancre sud-ouest | `/tp -96.5 252 181.5 45 0` |
| Ancre ouest | `/tp -96.5 230 0.5 90 0` |
| Ancre nord-ouest, récif | `/tp -102.5 404 -160.5 135 0` |
+77
View File
@@ -0,0 +1,77 @@
# WG-NATURE-190 — relief organique, déversoirs et butin des ruines
Branche `codex/natural-refinement-beta190`, graine de visite **42**, Minecraft 26.3.
Nouveau profil de laboratoire `refined`, preset `sanctuary_test:natural_refinement_v1`.
Les sauvegardes précédentes restent des témoins ; aucune régénération ni migration.
## Contrat de cet essai
Après la visite beta.189 : supprimer les terrasses systématiques du relief principal,
conserver quelques inflexions locales douces, des affleurements suivant la pente et
sans masque en cases de quatre blocs. Les captures du 30 septembre à 20:44 et 20:45
montrent le relief principal ; les îlots aériens ne sont pas la cause des paliers.
Comparer les débouchés voisins des étangs au lieu de retenir le premier rayon ;
privilégier une sortie courte, large de quatre ou cinq blocs et peu creusée.
Conserver les cavités, le portail et les ruines appréciés. Remplacer la table de
craft de chaque ruine par un coffre de matériel en fer enchanté.
Aucun calcul d’hydrologie régionale ajouté ; travail local borné, décoration existante.
## Réserve de conception, non implémentée
- Expansion à grandes surfaces étagées et falaises ciselées : conserver la variante
beta.189 comme référence, avec une profondeur et une verticalité adaptées au thème.
- Portails horizontaux : remplissage progressif avec une ressource renouvelable.
Perles d’Ender, source Endermen ou butin sont des pistes ; ressource, nombre,
recette et destination ne sont pas décidés. Aucun mécanisme d’activation ajouté ici.
## Vérifications
Compilation et génération/réouverture natives réussies, graine 42 :
`build/refined190b-cold.json` et `build/refined190b-warm.json`.
- 704 des 745 sommets échantillonnés gardent exactement la hauteur naturelle
antérieure aux terrasses ; 41 épaules retouchées, écart maximum 3 blocs.
30 246 densités des profondeurs et des îlots aériens identiques. Les corniches
fines sont conservées ; une première interpolation qui pouvait les supprimer
a été corrigée avant la visite.
- Une sortie d’étang de cinq blocs de large, depuis X=150, Y=244, Z=-157 à -153
vers X=154–155. Chenal de 4–5 blocs, dont une partie dans l’étang ; huit blocs
retirés. Bord de chute irrégulier, 64 blocs préremplis puis écoulement natif.
La recherche compare les ouvertures proches, reste bornée à dix blocs et
deux cascades, et renonce si aucune bouche assez large ne convient.
- 1 052 blocs de plage sèche, 434 plantes aquatiques, zéro tronc dans les
colonnes contrôlées des plages et étangs. Fonds : 1 337 sable, 249 gravier,
2 832 argile. Le choix du chenal ne crée pas de fond ou barrage artificiel.
- Quatre ruines conservées, coffres en (25,164,-63), (-7,148,-79),
(65,164,-79), (57,121,-79). Couvercles dégagés, table de butin conservée
après réouverture. Une ou deux pièces en fer par coffre, enchantements
de table de niveau 12–20 : armure, épée, pioche, hache ou pelle.
32 tirages vérifiés à froid, puis 32 à chaud ; aucune pièce non enchantée.
- Huit ancres, cartes du palais, gemmes, soufre, donjon et galerie contrôlés.
Ni nouvelle dimension ni activation des portails ajoutée.
Démarrage natif : 12,331 s à froid / 0,673 s à chaud ; avec toute la batterie
et le remplissage intégral des cartes : 81,505 s / 26,656 s. Plans locaux
berges/déversoirs : 174 / 170 ms. Zéro région d’hydrologie calculée.
Mesures obtenues pendant la suite de tests générale, sans garantie de durée
identique sur chaque machine. Le solo ne lance pas ces contrôles lourds.
`./gradlew check build assemblePack assembleTestPack` réussi en **9 min 22 s**,
avec **265 GameTests réussis**. Après les derniers correctifs validés par le labo
natif, le JAR optionnel a été réassemblé et le pack de test resynchronisé.
Ses classes et ressources correspondent aux fichiers compilés, et sa copie
assemblée est identique : `build/refined190-pack-receipt.json`.
Aucune publication de canal ni mise à jour Prism. La validation esthétique reste
celle de la prochaine visite ; les contrôles structurels ne la remplacent pas.
## Visite
Solo `Sanctuary-Natural-Refinement-190-Solo`, run `visite190`, profil `refined`,
graine 42. Copie neuve du monde de diagnostic arrêté, sauvegardes antérieures
préservées. Spectateur et commandes activés, vue 32, simulation 12, Vulkan.
Connexion confirmée à **21:01:12**, position (178,260,-146), face à la cascade.
Les 49 cartes et cadres horizontaux sont présents, complets et verrouillés ;
les huit ancres et le Bugrock sont revenus à l’état initial après les contrôles.
`build/refined190-saved-atlas.json`, `build/refined190-saved-blocks.json` et
`build/refined190-solo.log` conservent ces vérifications.
+103
View File
@@ -0,0 +1,103 @@
# WG-206 — dessous aminci et cavités froides
Branche `codex/north-cavities-beta206`, depuis beta.205 (`bf5df38`).
## Contrat
Le créateur valide une épaisseur variable sous le paysage du Nord, des cavités
froides et humides, et des failles ouvertes d’améthyste bordées de calcite et de
basalte. La surface et les grandes taïgas de beta.205 sont la référence.
La redistribution diorite / granit / andésite reste une proposition distincte.
Nouveau profil 206 uniquement, expansion Nord de 1024 blocs. Île de départ,
autres directions et profils historiques conservés. Aucun monde existant
converti, aucun chunk régénéré. Contrat des essais : nouveaux mondes de
développement, graines 42 et 0 ; activation et reprise du Nord explicitement
réservées à ces nouvelles sauvegardes de test. Aucun canal public ni instance
Prism à modifier.
## Implémentation
- Masque soustractif sous le bruit natif 205 : épaisseur cible continue de
40–99 blocs, contrôlée par deux bruits, dessous irrégulier. Les vingt blocs
supérieurs du champ natif restent protégés. Le masque ne rajoute aucune
montagne ni terrasse ; la roche déjà absente reste absente.
- Failles sinueuses dans la matière, avec améthyste, calcite et basalte lisse
organisés autour du même champ de fissure. Cristaux orientés vers l’air et
quelques blocs d’améthyste bourgeonnante.
- Dépôts de glace compacte et de glace bleue dans les cavités, argile localisée
et lichens. Biomes nordiques 206 distincts, sans les placements de champignons
ni les géodes fermées des profils précédents ; minerais conservés.
- Eau peu profonde dans le sol existant des cavités : un bloc de roche ou de
glace peut être remplacé par l’eau dans une poche de 6–96 blocs, sans ellipse
ni terrasse ajoutée. Contours en bruit mondial, fond et berges contrôlés sur
les blocs réels ; tout débouché est refusé. Recherche locale bornée, sans
grande hydrologie ni travail périodique en partie.
## Vérifications
- `./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north205,north206 -PsanctuaryAtlasOnly=true` :
succès (journal `build/north206-check-build-water.log`). Six GameTests ciblés
et contrôles purs passés. La suite native historique complète n’est pas revendiquée.
- Deux derniers garde-fous locaux des poches d’eau ont ensuite été recompilés :
lectures limitées aux chunks voisins et refus d’approfondir une poche déjà
remplie. Reconstruction finale avec `:sanctuary:runGameTest build assemblePack
assembleTestPack :sanctuary-test:exportDuoLaunch -x :sanctuary:check`, mêmes
propriétés de sélection : six tests repassés, succès en 22 s. Les contrôles
purs déjà passés n’ont pas été répétés pour ces deux garde-fous ; les essais
natifs ci-dessous utilisent ce JAR final.
- Profils Small, graines **42 et 0**, nouveaux mondes `north206-final` et
`north206-final0` : offrande réelle, rejet d’offrande incorrecte et de doublon,
interruption à 0/58, reprise des 58 chunks FULL et message SGA vérifiés.
Cinq igloos et une cave de guérison complets dans chaque monde.
- Comparaison au champ 205 de la même graine, sur une grille de relevé :
| Graine | Échantillons de roche 205 → 206 | Épaisseur maximale relevée 205 → 206 | Hauteurs de surface différentes | Plus grand tronc vérifié |
| --- | --- | --- | --- | --- |
| 42 | 17 968 → 9 279 (−48,4 %) | 179 → 91 blocs | 0 | 59 blocs |
| 0 | 17 084 → 8 887 (−48,0 %) | 177 → 90 blocs | 0 | 61 blocs |
- Dans les régions de faille examinées : 384 cristaux sur la graine 42 et 334
sur la graine 0 ; respectivement 2 429 et 2 425 blocs d’améthyste avec au moins
une face ouverte sur l’air. Calcite et basalte présents. Ce ne sont pas des
totaux à l’échelle de l’île.
- Eau vérifiée dans les blocs réels, avec fond et berges fermés : 11 positions
sur la graine 42 et 61 sur la graine 0. Cavités contenant air et glace, glaciers
de surface et taïgas géantes contrôlés. Ce contrôle des fondations ne remplace
pas un essai prolongé après modification des berges par le joueur.
- 3 456 cellules de biome stockées comparées au champ mondial par graine :
**aucune incohérence** aux jointures examinées. Densité de l’île initiale
identique octet par octet à la 205 pour Small, Medium et Large ; classes et
ressources historiques 205 conservées.
L’essai préliminaire a révélé un raccordement manquant du décor au générateur
hôte, corrigé avant ces essais finaux. La première recherche de petits bassins
strictement préexistants ne produisait pas d’eau vérifiable ; elle a été remplacée
par les poches peu profondes décrites ci-dessus. Une tentative démarrée avant la
fin de l’assemblage utilisait encore l’ancien JAR et n’est pas une preuve de la
version finale.
Les chiffres sont des échantillons, pas un inventaire exhaustif. Les essais
natifs supplémentaires génèrent plusieurs régions de visite et ne constituent
pas un benchmark comparatif de vitesse. Aucun essai Windows ni verdict esthétique
sur l’ensemble du paysage n’est revendiqué.
## Livraison locale
MRpack normal `build/Sanctuary-beta.206.mrpack`, copié dans `~/Downloads/` : ZIP
intact, JAR identique au build, trois tailles courantes et historiques présentes,
aucun mod Test ni sauvegarde embarqués. Minecraft 26.3 / Fabric Loader 0.19.5.
SHA-256 : `a0d2df3d207be0844af6cd4a3a578fd68c860dd0d3a28048f3b58725bb599fc7`.
Reçu : `build/north206-mrpack-receipt.json`.
Nouveau solo préparé depuis le monde 42 vérifié, dans `north206-visit`, avec
commandes, vue 32 chunks, simulation 5 et Vulkan. Arrivée près d’une paroi
d’améthyste ouverte en **(-463.5, 205, -1151.5)**. Autres repères de cette graine :
petite eau vers **(-311, 187, -732)** ; cavité glacée sous **(-416, 249, -728)** ;
grandes taïgas vers **(-176, 249, -720)**. Les altitudes de repère des taïgas et de
la cavité glacée sont celles de la surface, pas des téléportations souterraines.
Le client confirme le backend Vulkan et `NORTH206_VISIT_OPEN` à l’emplacement
prévu ; le rendu global reste à apprécier pendant la visite. Aucune publication
du canal, aucun déploiement Prism ni modification du monde 205.
+88
View File
@@ -0,0 +1,88 @@
# EXP-202 — étagement du Nord et village enneigé
Branche `codex/north-ecology-beta202`, depuis beta.201. Retour R021 et trois
captures du labo 201 examinées (12:11:22, 12:11:46 et 12:12:57, 4 octobre 2026).
Conserver les volumes, les cavités et les deux bassins 201, appréciés par le
joueur. Refaire uniquement leur écologie et leurs sols : taïga, vallées ouvertes,
podzol, épicéas géants natifs, neige progressive avec l'altitude, glaciers sur
les hauteurs. Fin des aplats indépendants et du camouflage glace/glace bleue.
Glace de cave limitée aux cavités protégées par une épaisseur de roche dans
chaque direction ; aucune couche glacée appliquée aux falaises ou au dessous.
Les cinq igloos doivent trouver une plaine réellement enneigée avant placement.
Les pics de glace restent vanilla, comme demandé en R020.
Nouveaux profils 202 et journal distinct, diamètre nordique 1024. Aucune migration
ni régénération d'un monde existant ; 200 et 201 gardent leurs générateurs.
L'île de départ et les autres directions restent inchangées. Le chantier est
isolé de la visite 201 encore ouverte. Validation native neuve Small/42, contrôles
numériques sur 0, 42 et 4736390610738281858 ; pas de campagne de captures.
## Réalisation
Le champ de densité et les deux bassins délèguent exactement à la génération
201. Seuls les sols, la végétation, la couverture neigeuse et le placement du
village changent. La limite de neige suit l'altitude, avec un versant nord plus
froid. Son épaisseur progresse de quelques couches à un bloc après la végétation.
Les glaciers sont réservés aux hauts versants ; aucune glace bleue ne peint
la surface. Les vallées restent en herbe, les grands boisements en podzol.
La taïga ordinaire et les épicéas géants réemploient les features 26.3 de taïga
et `old_growth_spruce_taiga`. Aucun arbre géant custom ajouté. Les pics utilisent
toujours `minecraft:ice_spike` et `minecraft:ice_patch`, sans remplacement des
features natives. Les matériaux de cave glacée nécessitent du recouvrement et
une assise rocheuse autour de la colonne ; les marges et dessous restent rocheux.
Les cinq igloos cherchent une zone sèche, entièrement enneigée et peu pentue,
avec classement par dénivelé. Aucun disque blanc ajouté sous le village.
Caches numériques bornés ; pas de simulation hydrologique supplémentaire.
## Vérifications du 4 octobre 2026
- `north202Smoke` : neuf couples graine/taille (0, 42, 4736390610738281858 ;
512/724/1024), égalité des colonnes et densités avec 201, présence de taïga,
vallées, neige progressive et glacier minoritaire, protection du dessous.
Recherche du village vérifiée aussi sur les graines 1 à 100. Toutes passent.
- Ressources historiques de génération inchangées, sauf le preset public qui
sélectionne désormais 202 et l'ajout du biome 202 au tag des ours polaires.
Les trois noise settings de l'île de départ sont identiques aux fichiers 201.
- Essai natif final : `build/worldgen-lab/north202-native-b`, Small, graine 42,
diamètre de l'expansion 1024. Offrande réelle, interruption à 0/58 chunks,
reprise, cinq igloos, une cave de guérison, relais de continuation orienté Nord.
- Échantillon de taïga : 1517 blocs de troncs, 7677 blocs de feuilles,
troncs atteignant 27 blocs, 13 empreintes de troncs larges, 3339 blocs de podzol.
Pics natifs : 2910 blocs de glace au-dessus du terrain, maximum sondé 43 blocs.
Ces nombres décrivent des échantillons, pas toute l'expansion.
- Village : 333 des 339 colonnes sondées hors maisons portent de la neige.
Lac : 8995 blocs de glace et 41795 blocs d'eau, sans fuite dans l'air.
Caverne sondée : 49 blocs glacés et 2585 blocs d'air. Bordure sondée sur
16 directions : 340 blocs rocheux, aucune glace compacte/bleue.
La validation esthétique reste celle de la visite. Pas de nouvelle campagne de
captures. Visite native Small/42 uniquement : Windows et Medium/Large natifs
ne sont pas vérifiés ici. Les sept autres directions restent provisoires.
## Livraison locale
`./gradlew check build assemblePack assembleTestPack
-PsanctuaryFocusedTests=operator,realtime -PsanctuaryAtlasOnly=true` : succès,
143 tâches, dont 126 exécutées ; sept GameTests ciblés et les smokes du projet.
La suite native historique complète n'a pas été relancée (limite documentée
pour beta.200). Logs : `build/north202-check-build.log` et
`build/north202-native-final.log`.
MRpack : `build/Sanctuary-Test-beta.202.mrpack`, copie identique dans Downloads
avec `Sanctuary-Test-beta.202-Guide.txt`. ZIP, versions 26.3 / Loader 0.19.5,
hashes Fabric API, deux JAR et leurs 2258 classes compilées vérifiés.
Reçu local : `build/north202-artifact.json`.
Taille : 12407853 octets ; SHA-256 :
`b5ecdfcb2c4b1988f9402653a16c823b50f0661e8b1db0f0e7d6c21e9841f6f8`.
Aucun monde inclus dans le MRpack. Aucun canal public ni instance Prism modifié.
Visite neuve `Sanctuary-North-202-42`, issue de l'essai natif final, créatif,
commandes activées, Vulkan, vue 32, simulation 4. Départ en vol près du village.
Village `(-212,191,-1292)`, taïga géante `(144,215,-976)`, lac `(-247,258,-765)`,
pics vers `(-208,281,-880)`, relais `(-128,202,-1240)`.
Ouverture confirmée à 12:41:46 par `NORTH202_VISIT_OPEN`, joueur
`(-160,228,-1247)` ; log `build/north202-visit-client.log`.
+120
View File
@@ -0,0 +1,120 @@
# EXP-200 — premier Nord glacial
Branche `codex/north-expansion-beta200`, depuis beta.199. Retours R015–R017.
## Résultat visé
Un continent nordique de diamètre nominal 2048 : crêtes, pics, vallées de taïga
neigeuse, neige poudreuse localisée, cavernes de glace et lacs gelés fermés.
Chèvres et ours polaires natifs de Minecraft 26.3 (choix confirmé).
Un village de plusieurs igloos ; un seul contient le laboratoire souterrain
vanilla avec villageois zombie. Pas d'autre famille de structures dans cette
première tranche. Le Sud, l'Est, l'Ouest et les diagonales seront travaillés à part.
## Placement et ouverture
L'identité du relais reste celle de son secteur. Recherche proche dans un
éventail de ±15° devant l'ancre, sans basculer dans une autre direction.
La première version 200 porte le Nord à 2048 ; les sept autres reliefs gardent
leur taille/profil provisoire de 199. Le relais de continuation du Nord conserve
la direction, le climat et la taille du Nord.
Toute l'emprise est vérifiée vierge, réservée durablement et publiée avant les
travaux. À cette échelle, `ready` signifie accès et relais préparés ; le reste
est généré nativement pendant l'exploration. L'annonce SGA décrit cette ouverture,
pas une pré-génération intégrale. Préparation bornée, sans simulation hydrologique
globale ni réutilisation silencieuse de chunks déjà explorés.
## Contrat des sauvegardes
Nouveaux profils `shared_island200_small/medium/large`, journal distinct
`sanctuary-lab-expansions200`. Aucun monde existant modifié ou migré ; les profils
et ressources 196–199 restent inchangés. IDs historiques conservés. Les essais
activent uniquement des expansions dans des mondes de développement neufs,
graine 42 puis relevés déterministes sur 0 et 4736390610738281858.
## Vérifications prévues
Direction et diamètre, déterminisme, cavités, confinement des eaux, village
et laboratoire habitable, vraie activation, sauvegarde et reprise. Compilation,
`check build` et assemblages. Ne pas confondre vérification technique et validation
esthétique : le rendu reste une première version à visiter.
## Implantation et contrôles intermédiaires
Le champ nordique compose des crêtes déformées, des sommets secondaires et des
vallées, puis soustrait des passages et chambres 3D. Cache numérique borné par
worker ; aucune lecture de chunks voisins pour dessiner le terrain. Six biomes
nordiques reprennent l'écologie native de 26.3 ; les sources d'eau/lave dispersées
et salles de monstres vanilla sont retirées de ces seuls profils. Les bassins
ont un fond rocheux continu et une couverture de glace, sans hydrologie globale.
Village : cinq igloos natifs orientés et ajustés individuellement au sol. Un
seul laboratoire, avec échelle, coffre vanilla, potion de faiblesse, villageois
et villageois zombie persistants. Les arbres évitent les maisons et les lacs.
La faune initiale utilise les attributs du biome à la surface réelle, car la
sélection vanilla à Y=1600 échantillonnait le vide ; règles de spawn natives
conservées. Ours polaires également admis sur la glace des lacs.
- `north200Smoke` : 9 couples graine/taille, huit éventails, relief/cavités,
bassins analytiquement fermés, journal 2048 et refus de 2048 en génération 199.
- Essai intermédiaire Small/42, 2 Gio : vraie offrande nord, interruption à
0/58 chunks, puis reprise. Village de cinq igloos et un laboratoire contrôlés ;
lac avec 3475 blocs de glace et 10525 blocs d'eau, sans voisin d'air sous l'eau ;
136 blocs de glace et 1926 blocs d'air dans les colonnes de caverne sondées.
Ce sont des sondages locaux, pas les totaux du continent.
- Le premier passage a révélé un barreau manquant sous la trappe : raccord
corrigé et vérifié lors du second passage. Les essais antérieurs restent
conservés sous `build/worldgen-lab/north200-native-a` et `north200-native-b`.
- Les 148 ressources historiques de génération du module Test restent identiques
à beta.199 (hors preset public, qui sélectionne maintenant 200).
## Essai final et livraison locale — 4 octobre 2026
Le parcours serveur final `north200-native-final/small/42` répète l'activation
réelle et l'interruption/reprise sur les sources livrées. Les 58 chunks d'accès
et de relais passent à FULL ; cinq igloos, un laboratoire, le lac et la cavité
glacée sont vérifiés. Les entités sauvegardées comprennent six ours polaires,
trois renards, huit lapins, un villageois et un villageois zombie. Aucune chèvre
observée dans ce petit échantillon : leurs règles natives sont présentes dans
les sommets et pentes, sans validation d'une rencontre dans ce parcours.
Le client Vulkan a ouvert une copie de visite neuve, `Sanctuary-North-200-42`,
avec confirmation `NORTH200_VISIT_OPEN` à `(-200,224,-968)`. Créatif, commandes,
vue 32 chunks et simulation 4 ; shaders désactivés. Le village se trouve autour
de `(-200,212,-988)`, la trappe spéciale vers `(-193,210,-961)`, le lac sondé en
`(-64,187,-1204)` et le relais suivant en `(-176,215,-2121)`.
Archive locale : `build/Sanctuary-Test-beta.200.mrpack`, également copiée dans
`/Users/koka/Downloads/`, avec `Sanctuary-Test-beta.200-Guide.txt`.
12 366 771 octets ; SHA-256 :
`2a29b35613f95540ec9d910e043a1f6f26b2dfe7d6d95c50997ba4bbde203cdc`.
Intégrité ZIP, version, dépendances Minecraft 26.3 / Fabric Loader 0.19.5,
empreintes Fabric API, deux JAR identiques au build et 2246 classes compilées
vérifiés. Les trois tailles sont présentes ; aucune sauvegarde embarquée.
Reçu : `build/north200-artifact.json`. Aucun canal public ni Prism synchronisé.
La commande complète `check build assemblePack assembleTestPack` a été lancée,
puis interrompue volontairement pendant
`retainedHydrologySurvivesNativeDecoration` (ancienne génération 24, préparation
de 112 chunks FULL). Les captures de threads montrent l'attente de génération ;
elles ne démontrent pas un interblocage. Cette suite générale n'est pas validée.
Logs : `build/north200-check-build.log`, `north200-fullcheck-threads*.txt`.
Les essais serveur nordiques sont distincts de cette suite historique.
Les sept GameTests `operator,realtime` passent avec le fixture plat
`-PsanctuaryAtlasOnly=true`, indépendamment de l'essai natif nordique.
Cette sélection ne remplace pas les 265 tests de la suite générale.
La commande `./gradlew check build assemblePack assembleTestPack
-PsanctuaryFocusedTests=operator,realtime -PsanctuaryAtlasOnly=true` termine avec
succès : 141 tâches, dont 110 exécutées et 31 à jour. Elle inclut les tests
numériques, notamment `north200Smoke`. Log complet :
`build/north200-check-build-focused.log`. Archive revérifiée après l'assemblage
final, identique aux JAR et classes finaux ; daemon de build arrêté ensuite.
Limites : validation native détaillée sur Small/42, neuf couples graine/taille
pour les contrôles numériques, pas de lancement Windows ni de visite native
Medium/Large sur cette version. Les 2048 blocs désignent le diamètre nominal,
pas une pré-génération intégrale. Le démarrage à 32 chunks a produit des retards
de ticks avec les contrôles et un autre client simultanés sur le Mac 8 Gio :
aucune conclusion de fluidité ni correction des saccades n'est revendiquée.
+87
View File
@@ -0,0 +1,87 @@
# EXP-203 — fractures, lisières et taïga géante
Branche `codex/north-fracture-beta203`, depuis beta.202. Retour R022.
Le rendu 202 est globalement validé. Passe ciblée demandée : ajouter de fortes
variations locales de volume et des trous par bruit 3D, retirer la neige ajoutée
après la végétation, brouiller les limites du podzol, donner aux grands épicéas
une hauteur pouvant atteindre 64 et varier les matières des sommets glacés.
Aucun nouveau village : la proposition supplémentaire est retirée par le joueur.
Les cinq igloos existants restent présents.
Nouveaux profils 203 seulement, Nord 1024. Aucun monde existant régénéré ni
migré ; profils 200–202 inchangés. Bassins et basses plaines d'accueil protégés
de la déformation. Pics de glace vanilla conservés. Arbres avec moteur natif,
configuration propre au biome géant ; aucune modification globale des épicéas.
Pas de simulation d'érosion ou d'hydrologie supplémentaire, caches bornés.
## Réalisation
Le champ 203 combine des déplacements verticaux locaux (deux échelles de bruit)
et un bruit volumique négatif de plus grande portée. Les nouvelles poches
peuvent traverser le toit ou le dessous, contrairement aux caves fermées 202.
Le bruit est atténué sur les basses plaines, les bords et tout autour des lacs.
Les seuils de sommet restent lisibles ; le détail 3D module les roches et glaces.
La passe de neige après décoration n'est pas appelée pour 203. Les prairies
froides gardent leur herbe ; la neige demeure comme matériau de sommet,
substrat nécessaire aux pics vanilla et matériau des igloos existants.
Le champ de podzol comporte deux fréquences de détail aux lisières. Le
`alter_ground` circulaire des nouveaux grands arbres est supprimé.
Les arbres réemploient `giant_trunk_placer` et `mega_pine_foliage_placer` de
Minecraft 26.3. Configuration locale : hauteur 32 + aléa 0–16 + aléa 0–16,
soit 32 à 64 blocs, couronne de 18–24 ; mélange de géants et de petits épicéas.
Les features `ice_spike` / `ice_patch` restent natives et inchangées.
## Contrôles
`north203Smoke` passe sur neuf couples graine/taille (0, 42,
4736390610738281858 ; Small/Medium/Large). Les déplacements locaux sondés vont
jusqu'à environ −62 / +56 blocs selon le cas. Ouvertures de surface présentes,
densité bornée, lacs et leurs coques inchangés, lisières de podzol irrégulières.
Recherche des cinq igloos vérifiée également sur les graines 1 à 32.
Les ressources worldgen historiques sont inchangées, hors sélection du nouveau
preset public et ajout du biome 203 au tag des ours polaires. Les noise settings
de l'île de départ restent identiques à 202. Aucun test visuel Windows ni
nouvelle campagne de captures : le rendu est à juger dans le labo.
Essai natif final : `build/worldgen-lab/north203-native-b`, Small/graine 42.
Vraie offrande, interruption à 0/58 chunks, reprise et relais prêts. Cinq igloos
et un laboratoire conservés. Recherche de cave orientée vers un intérieur
suffisamment épais, plutôt que le sommet le plus haut désormais fracturé.
Dans les échantillons : 4218 blocs de troncs, 10450 de feuilles, 21 empreintes
de troncs larges ; tronc le plus haut mesuré 59 blocs (plafond configuré 64).
Sommet : 309 blocs de glace bleue, 63 de glace ordinaire, 2154 de glace compacte,
1219 de neige pleine et 1694 de roche. Pics vanilla : maximum sondé 13 blocs
au-dessus du terrain. Prairie : zéro couche de neige parmi 339 colonnes.
Lac : 8995 blocs de glace et 41795 d'eau, sans fuite ; caverne sondée : 226 blocs
glacés et 1878 d'air. Bordure : 339 blocs rocheux, aucune glace compacte/bleue.
Il s'agit de contrôles locaux, pas d'un comptage de toute l'expansion.
## Livraison
`./gradlew check build assemblePack assembleTestPack
-PsanctuaryFocusedTests=operator,realtime -PsanctuaryAtlasOnly=true` : succès,
144 tâches dont 120 exécutées, sept GameTests ciblés et les smokes du projet.
La suite native historique complète n'a pas été relancée (limite beta.200).
Logs : `build/north203-check-build.log` et `build/north203-native-final.log`.
MRpack vérifié : `build/Sanctuary-Test-beta.203.mrpack`, copie identique dans
Downloads avec le guide. Archives, versions, dépendances, empreintes Fabric API,
JAR et 2265 classes compilées vérifiés ; reçu `build/north203-artifact.json`.
12433661 octets ; SHA-256 :
`ba160b4134c0b9dbe402e1834bdbec4f5561bfd6bd9dc147590dd76ee30dbf4f`.
Visite neuve `Sanctuary-North-203-42`, issue de l'essai natif final. Créatif,
commandes activées, Vulkan, vue 32, simulation 4 ; départ au-dessus de la taïga.
Village `(-212,191,-1292)`, forêt `(144,215,-976)`, pics `(-208,278,-944)`,
premier lac `(-247,258,-765)`. Aucun canal public ni instance Prism modifié.
Pas de sauvegarde embarquée dans le pack ni de revendication sur les saccades.
Essai natif Small/42 seulement ; Medium/Large sont contrôlés numériquement.
Ouverture confirmée à 13:12:20 par `NORTH203_VISIT_OPEN`, départ
`(196,292,-931)`, backend Vulkan confirmé dans `build/north203-visit-client.log`.
+90
View File
@@ -0,0 +1,90 @@
# EXP-201 — Nord compact, glacier et bosquets
Branche `codex/north-glacier-beta201`, depuis beta.200 ; retours joueur R019–R020.
## Résultat demandé
Le diamètre du Nord passe de 2048 à 1024 blocs. Remplacer la nappe blanche perçue
par un paysage de glace lisible : pics de glace, glacier, deux lacs gelés visibles,
bosquets localisés et contraste roche/glace/neige. Conserver les cinq igloos et
le laboratoire avec villageois zombie. Les lacs doivent contenir de l'eau sous
leur glace ; la végétation doit être réellement générée, pas seulement déclarée.
Les pics utilisent explicitement `minecraft:ice_spike` et `minecraft:ice_patch`
de Minecraft 26.3, avec leurs placements natifs. Aucune forme de pic recodée.
Le Nord ne doit pas devenir le catalogue de tous les biomes froids. Son identité
est le glacier habité ; les grandes forêts boréales, côtes froides et autres
paysages restent des pistes pour NO/NE. Leur répartition n'est pas décidée ici.
## Contrat de génération
Nouveaux profils 201 et journal `sanctuary-lab-expansions201`, destinés uniquement
aux nouveaux mondes. Les profils et le champ nordique 200 restent disponibles
pour les sauvegardes historiques ; aucune conversion des expansions 2048 déjà
créées, ni régénération de chunks. Île de départ Small/Medium/Large inchangée.
Placement dans l'éventail existant de ±15°. Préparation bornée de l'arrivée et du
relais, puis exploration. Les sept autres directions restent provisoires.
## Vérifications attendues
Contrôle de taille et de direction, stabilité de la génération 200, proportions
et visibilité des surfaces glaciaires, lacs fermés, relief vertical, bosquets et
village. Vérification native de vrais troncs/feuilles, glace de surface non
recouverte et pics élevés. Graines numériques 0, 42 et 4736390610738281858 ; visite
native neuve Small/42. Pas de campagne de screenshots ni d'hydrologie globale.
Les contrôles techniques ne remplacent pas le retour esthétique du joueur.
## Intégration
La 200 posait une couche de neige pendant le traitement du sol, avant les
features végétales ; les arbres natifs de taïga passent par les saplings
`spruce_checked` / `pine_checked`, qui exigent un support viable. La 201 laisse
le sol des bosquets en herbe jusqu'à leur plantation. Les lacs et le glacier ne
reçoivent plus la feature `freeze_top_layer`, afin que leur glace reste visible.
Les zones de pics conservent au contraire le bloc de neige requis par la feature
native `minecraft:spike`. Ses références et sa fréquence restent vanilla.
Le substrat compact associe une crête, des épaules glaciaires, deux champs de
pics natifs, deux bosquets et deux bassins fermés. Caches numériques bornés ;
aucune simulation hydrologique globale. Le village est rapproché du premier lac.
Le relief, les matériaux et le choix de biomes de la 200 gardent leur branche
de génération historique.
## Résultats — 4 octobre 2026
- `north201Smoke` : neuf couples graine/taille, Nord 1024, relief, parts de glace,
bosquets, lacs et champs de pics, confinement des bassins, déterminisme et
routage historique 200. `north200Smoke` reste passant. Les 155 ressources
historiques worldgen du module Test restent identiques, hors preset public.
- Serveur neuf Small/42, `build/worldgen-lab/north201-native-a` : vraie offrande,
interruption à 0/58 chunks, reprise et accès préparés. Cinq igloos, une cave
avec trappe/échelle/coffre/potion ; relais de continuation orienté Nord.
- Échantillon du bosquet : 395 blocs de troncs et 3294 blocs de feuilles
d'épicéa, répartis sur 56 colonnes de troncs (pas un comptage d'arbres entiers).
Champ de pics natifs : 1838 blocs de glace compacte au-dessus du terrain,
maximum sondé de 11 blocs. Lac : 8995 blocs de couverture gelée et 41795 blocs
d'eau ; 7602 surfaces de glace visibles contrôlées, zéro couche de neige dessus.
Caverne : 561 blocs de glace et 2585 blocs d'air sondés. Totaux locaux uniquement.
- `./gradlew check build assemblePack assembleTestPack
-PsanctuaryFocusedTests=operator,realtime -PsanctuaryAtlasOnly=true` : succès,
sept GameTests ciblés et tous les smokes associés, 142 tâches dont 118 exécutées.
La suite native historique complète n'a pas été relancée (limite beta.200).
Logs : `build/north201-check-build.log` et `build/north201-native-a.log`.
Livraison locale : `build/Sanctuary-Test-beta.201.mrpack`, copie dans Downloads
avec le guide. 12 386 623 octets ; SHA-256 :
`37925f012e4096c253f25e573305237e71114448d866a57f3fbad6e3da6b3d89`.
ZIP, dépendances 26.3 / Loader 0.19.5, empreintes Fabric API, JAR et 2252 classes
compilées vérifiés. Les trois tailles sont incluses, aucune sauvegarde embarquée.
Reçu : `build/north201-artifact.json`. Aucun canal public ni Prism modifié.
Visite préparée : `Sanctuary-North-201-42`, nouveau monde issu de l'essai natif.
Départ près du lac en `(-142,323,-705)`, créatif, commandes, Vulkan, vue 32 et
simulation 4. Ouverture confirmée par `NORTH201_VISIT_OPEN` dans
`build/north201-visit-client.log`. Village `(-128,205,-637)`, lac `(-247,258,-765)`, bosquet
`(-324,258,-780)`, champ de pics vers `(-273,-1059)`, relais `(-128,202,-1240)`.
Limites : visite native Small/42 seulement, pas d'essai Windows ou Medium/Large
natif sur cette version. Pas de revendication sur les saccades. Les paysages
NO/NE ne sont pas implémentés ; les anciens mondes ne changent pas de taille.
+129
View File
@@ -0,0 +1,129 @@
# WG-207 — neige, couronnes et manoir du Nord
Branche `codex/north-landscape-beta207`, depuis beta.206 (`6f78054`).
## Contrat
Accord du créateur sur les trois suites du retour R004 : taïga partiellement
enneigée, reliefs Voronoi localisés sur les hauts plateaux et manoir procédural
inspiré du manoir vanilla. Le bois du manoir doit être de l’épicéa (spruce).
Conserver le diamètre de 1024 blocs, le dessous aminci et les grandes failles
d’améthyste validés en visite. Ne pas transformer toute la forêt en neige.
Profil neuf 207 exclusivement. Les profils 206 et antérieurs gardent leur
génération. Aucun monde existant modifié ni chunk régénéré. Contrat des essais :
nouveaux mondes de développement, graines 42 et 0, avec activation et reprise
du Nord pour contrôler la génération et préparer une visite. Aucun déploiement
Prism, publication du canal ou modification de sauvegarde personnelle.
## Implémentation
- Jusqu’à cinq couronnes sur des épaules hautes et soutenues, avec distances
de Voronoi, déformation du contour par bruit et cols entre les sommets.
Ajout local de quelques dizaines de blocs, plafond à Y=308 ; aucune terrasse
globale. Le champ de densité sous le toit initial reste celui de la 206.
- Nappes de neige de plusieurs échelles sur la taïga, avec deux variantes de
biomes froids et les variantes tempérées conservées. Placement sur le sol
réel sous la canopée, remplacement des petites plantes, état enneigé de
l’herbe/podzol. Les troncs, l’eau et les plantes non admissibles sont protégés.
La passe lit les cellules de biome déjà stockées au lieu de refaire le calcul
complet des cavités pour chaque colonne de neige.
- Assemblage natif des pièces du manoir, avec disposition dépendante de la
graine, pièces meublées, coffres et occupants vanilla. Conversion locale des
bois principaux en épicéa, panneaux en calcite, soubassements en tuf taillé et
tapis froids. Les propriétés des escaliers, dalles et portes sont conservées.
- Recherche bornée d’un site adapté à l’emprise réelle, hors igloos, arrivée,
relais et couronnes ; contrôle des appuis colonne par colonne. Aucun
terrassement massif ni fondation sans limite vers le vide. Si une graine ne
possède pas de site admissible, le manoir est omis avec un diagnostic plutôt
que de faire échouer l’expansion.
- Approche de trois blocs de large en escaliers de tuf, raccordée au terrain
devant l’entrée ; appuis et dégagement contrôlés dans les essais natifs.
## Vérifications de compilation
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north206,north207 -PsanctuaryAtlasOnly=true` :
succès, contrôles purs et six GameTests ciblés passés. Journal :
`build/north207-check-build.log` (5 min 42 s).
Après les dernières corrections locales (accès, portillon en épicéa et lecture
des biomes pour la neige), reconstruction et six GameTests repassés avec
`:sanctuary:runGameTest build assemblePack assembleTestPack
:sanctuary-test:exportDuoLaunch -x :sanctuary:check`, mêmes propriétés de sélection.
Journal final : `build/north207-final2-build.log`, succès en 55 s. Les contrôles
purs historiques déjà passés n’ont pas été répétés à cette étape. La suite
historique complète des GameTests n’est pas revendiquée.
Les tests ciblés vérifient le maintien des anciens presets dans les trois tailles,
la conservation du dessous 206, l’étendue limitée du nouveau relief et les
propriétés d’orientation des escaliers/portes après conversion en épicéa.
Les trois fichiers de densité de l’île initiale sont identiques à ceux de la 206.
## Essais natifs sur le build final
Profils Small, nouveaux mondes `north207-final` (42) et `north207-final0` (0).
Offrande réelle, refus des offrandes incorrectes et des doublons, interruption
à 0/58 puis reprise des chunks préparés et annonce SGA : succès. Cinq igloos
et une cave de guérison complets sur chaque graine.
| Relevé | Graine 42 | Graine 0 |
| --- | --- | --- |
| Couronnes / ajout maximal relevé | 5 / 52 blocs | 5 / 45 blocs |
| Colonnes relevées avec élévation > 2 blocs / autres | 191 / 1 767 | 192 / 1 790 |
| Échantillons profonds identiques à la 206 | 52 989 | 51 958 |
| Améthyste / faces ouvertes dans la région inspectée | 7 731 / 1 928 | 12 494 / 3 567 |
| Sols enneigés dans la zone de taïga enneigée inspectée | 2 225 | 1 514 |
| Sols dégagés / enneigés dans la taïga tempérée inspectée | 2 209 / 0 | 2 372 / 0 |
| Pièces natives du manoir | 544 | 547 |
| Fondation maximale du manoir | 5 blocs | 6 blocs |
| Coffres conservant une table de butin native | 5 | 5 |
| Cellules de biome stockées contrôlées / incohérences | 1 944 / 0 | 1 944 / 0 |
Les deux manoirs ont des planchers et escaliers en épicéa, des panneaux en
calcite et du tuf taillé. Aucun bloc de planches de chêne/chêne noir ni feuille
d’épicéa envahissante dans les volumes examinés. L’approche possède trois
marches centrales contrôlées avec support et deux blocs d’air de dégagement.
Les autres coffres des pièces vanilla peuvent être des rangements sans table
de butin : ne pas confondre nombre total de coffres et récompenses.
Ces nombres sont des relevés locaux ou sur grille, pas un inventaire de l’île.
L’essai préliminaire `north207-a` avait déjà passé les contrôles de paysage et
de manoir ; les deux essais ci-dessus utilisent le JAR final, après optimisation
de la passe de neige et vérification supplémentaire de l’accès et du butin.
Les essais finaux tournaient en parallèle : leurs durées ne constituent pas
une comparaison de performance avec la 206.
## Livraison locale
MRpack normal `build/Sanctuary-beta.207.mrpack`, copié dans `~/Downloads/`.
ZIP intact, JAR identique au build final, profils courants et historiques des
trois tailles présents, aucun mod Test ni monde embarqué. Minecraft 26.3,
Fabric Loader 0.19.5. Reçu : `build/north207-mrpack-receipt.json`.
SHA-256 : `1f6caca543dddea4e961bba6737a9d4a0e2fbb2935fb17a3c2c94d8f1a7a635d`.
Nouvelle visite `north207-visit`, graine 42, copiée depuis le monde vérifié et
arrêté. Vue 32 chunks, simulation 5, commandes et vol créatif. Position initiale
préparée : **(49.5, 302, -1285.5)**, face au manoir. Repères de visite :
- Manoir : **(-27, 252, -1244)**.
- Taïga enneigée : **(-192, 251, -704)**.
- Taïga dégagée : **(32, 253, -720)**.
- Sommet ajouté : **(-448, 303, -1008)**.
Les repères indiquent les régions contrôlées ; certains sont au-dessus du sol
pour la visite en vol. Aucun canal public, serveur personnel ou instance Prism
modifié. Les mondes précédents sont conservés.
Le client confirme Vulkan / MoltenVK et `NORTH207_VISIT_OPEN` à **(49, 302,
-1286)** le 5 octobre à 02:28. La visite est ouverte ; le rendu reste à juger
par le créateur, sans prétendre à une inspection graphique exhaustive.
## Limites
Le manoir utilise les pièces et le butin natifs avec une palette propre au Nord.
Il ne possède pas de nouvelle entrée `/locate` ; son placement appartient au
générateur local. L’admission peut omettre le manoir sur une graine sans appui
admissible. Aucun jugement esthétique global, essai Windows ou benchmark
comparatif n’est déduit des vérifications techniques.
+77
View File
@@ -0,0 +1,77 @@
# WG-205 — Nord en bruit 3D natif
Branche `codex/north-noise-beta205`, depuis beta.204 (`2463db7`).
Retour : montagnes reliées et trop étirées, démarcations de biomes suivant les
chunks. Retirer la surélévation Peaks et les masses ajoutées au-dessus du bruit
de base ; habiller ensuite les surfaces réellement générées.
Contrat : nouveau profil 205 uniquement, Nord de 1024 blocs. Taïga géante,
glaces et cinq igloos conservés. Île de départ et profils 200–204 inchangés.
Aucune migration, aucun ancien chunk modifié. Essais sur nouveaux mondes de
développement, graines 42 et 0. Publication et installation Prism non demandées.
## Changements
Le Nord 204 cumulait la déformation verticale Peaks, un agrandissement horizontal
×2 / vertical √2 et les corps supérieurs de la densité Population. Le profil 205
utilise le champ natif sans ces déformations : enveloppe de 1024 directement,
bruit à son échelle d'origine et cavités conservées. Le champ n'est pas rehaussé
après coup pour former une chaîne de montagnes. Les anciennes classes 204 restent
inchangées et les autres directions conservent leur relief.
Le champ d'écologie 204 arrondissait X/Z par groupes de huit blocs. La hauteur,
la pente et les seuils de glace pouvaient alors changer d'un carré au suivant.
Le nouveau lecteur interpole les hauteurs entre les mesures ; il mesure à nouveau
une colonne quand un voisin est vide, sans fabriquer un sol par interpolation.
Les sols sont appliqués sur la vraie hauteur du chunk déjà généré. La ligne de
froid est ajustée au nouveau relief moins élevé, avec taïga géante, neige, pics
natifs et cavernes glacées ; les igloos cherchent des épaules soutenues.
## Vérifications — 5 octobre 2026
- Cinq GameTests ciblés passés (`base204,north205`, plus contrôle commun) :
presets courants/historiques sans Test, pente continue sur les frontières X/Z
négatives et positives, indépendance des workers, absence d'étirement et de
surélévation 205, conservation de l'ancien comportement 204 et des autres axes.
- Small, graine 42, monde neuf `north205-final` : offrande réelle, refus des doublons,
interruption/reprise, préparation de 58 chunks, cinq igloos et une cave de
guérison vérifiés. Centre `(-128, -944)`, arrivée `(-160, 253, -1024)`.
- Même graine : échantillons de surface Y=87–251, épaisseur maximale 179 blocs,
taïga géante avec un tronc de 59 blocs, cavité avec air et glace, glacier présent.
Zéro incohérence entre les 3 456 cellules de biome sauvegardées aux jointures
des zones contrôlées et le champ mondial. Reçus dans
`build/worldgen-lab/north205-final/small/42/`.
- Le premier diagnostic de grotte pointait le massif le plus épais, contenant
surtout de la roche. Le contrôle cherche maintenant une poche vide sous une
couverture suffisante avant de vérifier air et glace dans les chunks réels.
Le terrain n'a pas été modifié pour satisfaire ce diagnostic.
- Small, graine 0, monde neuf `north205-final0` : mêmes contrôles de l'expansion,
cinq igloos, cavernes et glaciers passés. Échantillons Y=84–255, tronc maximal
61 blocs. Zéro incohérence sur 3 456 cellules de biome supplémentaires. Le
contrôle de glacier inclut la glace normale, adaptée à ces altitudes, et
exige plus de 50 blocs glacés dans la zone examinée ; il ne suppose plus la
présence obligatoire de glace compacte ou bleue. La graine 0 en contient 117.
- `./gradlew check build assemblePack assembleTestPack
-PsanctuaryFocusedTests=base204,north205 -PsanctuaryAtlasOnly=true` : succès,
journal `build/north205-check-build.log`. La suite native complète n'est pas
revendiquée. Après la dernière correction du diagnostic Test, sa compilation,
ses tests et son build ont également passé ; une répétition inutile des tâches
du mod principal a été interrompue. Les deux essais natifs finaux utilisent
ce diagnostic corrigé. Le JAR du mod normal n'a pas changé après sa validation.
- MRpack normal exporté et vérifié : contenu ZIP intact, JAR identique au build,
preset public 205, profils historiques présents, aucun Test ou monde embarqué.
SHA-256 : `63023e8ff355afb94223bd697a71ae1d6ad72c80dca2f5c502664627f3d8d572`.
Les mesures de hauteur sont des échantillons, pas un relevé exhaustif de tous les blocs. La
continuité numérique et les biomes stockés sont testés ; l'appréciation visuelle
des transitions reste à confirmer en visite. Aucune validation Windows revendiquée.
## Livraison locale
`build/Sanctuary-beta.205.mrpack`, copié dans `~/Downloads/`. Une copie neuve du
monde vérifié est ouverte dans `north205-play`, graine 42, en créatif avec
commandes autorisées, Vulkan, vue 32 chunks et simulation 5. La visite commence
au-dessus de la taïga en `(-143.5, 331, -677.5)` ; `NORTH205_VISIT_OPEN` et
le backend Vulkan sont confirmés dans le journal. Aucun monde 204 n'est converti.
Le canal public et l'instance Prism ne sont pas modifiés.
+113
View File
@@ -0,0 +1,113 @@
# WG-208 — crêtes et replats glacés du Nord
Branche `codex/north-ridges-beta208`, depuis beta.207 (`bb10c24`).
## Contrat
Dernier affinage demandé avant clôture du Nord : remplacer les couronnes trop
rondes par des arêtes anguleuses, des sommets pointus et des entailles d'érosion.
Ajouter quelques replats à différentes altitudes avec des poches de glace.
Les formations de glace au-dessus restent une piste : privilégier quelques
aiguilles naturelles localisées, sans ajouter de bâtiment.
Conserver la taille de 1024 blocs, la taïga partiellement enneigée, le dessous
aminci, les failles d'améthyste, les igloos et le manoir en épicéa validés.
Profil neuf 208 uniquement. Les générations 207 et antérieures restent
disponibles et inchangées. Essais autorisés sur de nouveaux mondes de
développement, graines 42 et 0, avec activation/reprise du Nord. Préparer une
nouvelle visite solo Vulkan à 32 chunks ; aucune sauvegarde existante modifiée.
Aucun déploiement Prism ni publication du canal public.
## Réalisation
- Les mêmes cinq sites de relief qu'en 207 reçoivent des faces asymétriques.
La distance aux sites Voronoi sépare les massifs ; cinq plans inégaux dessinent
leurs arêtes. La pente reste marquée près du sommet au lieu de s'y arrondir.
Des entailles par bruit cohérent interrompent localement les flancs. Il ne
s'agit pas d'une simulation d'érosion ou d'une hydrologie globale.
- Jusqu'à deux replats par massif, de rayons 15 et 19 blocs, à des hauteurs
différentes. Ils sont admis uniquement au-dessus du toit rocheux existant,
avec raccordement progressif sur leur bord. Aucune quantification générale
des altitudes ni succession de terrasses sur toute l'île.
- Petites cuvettes de glace sur glace compacte, encaissées d'un bloc, et
aiguilles de glace sur certaines rives. Ces poches sont gelées jusqu'au fond :
elles n'ajoutent pas d'écoulements ni de nouvelles cascades.
- Densité profonde de la 206 conservée ; écologie et neige de la 207 réutilisées,
y compris leurs identifiants de biomes. Manoir et igloos adaptés au nouveau
champ de relief, avec leurs palettes et contenus conservés. Les anciens
générateurs et ressources 207 restent disponibles.
- Les calculs de sommet sont mémorisés par colonne dans un cache borné par
worker. Aucun parcours global supplémentaire à chaque tick.
## Vérification
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north207,north208 -PsanctuaryAtlasOnly=true` :
succès en 4 min 47 s, contrôles purs et sept GameTests ciblés passés.
Journal : `build/north208-check-build.log`. Les tests vérifient notamment les
anciens presets des trois tailles, le maintien de la densité profonde, le dénivelé
près des sommets, les appuis des cuvettes et le déterminisme entre workers.
La suite historique complète des GameTests n'est pas revendiquée.
Les dernières additions au diagnostic et au lanceur du module Test sont
recompilées et assemblées séparément, sans répéter les contrôles purs déjà passés :
`build/north208-lab-final.log`, succès. Les trois fichiers de densité de l'île
principale sont strictement identiques à la 207.
Le premier essai 42 passe tous les contrôles. Sur la graine 0, un replat
pouvait remplir un creux trop profond (élévation locale relevée de 94 blocs).
L'admission exige désormais un toit proche sur toute l'emprise ; une garde
par colonne empêche de combler les trous profonds. Un test de régression
reproduit une cavité sous un replat. Reconstruction finale avec `:sanctuary:runGameTest build assemblePack assembleTestPack
:sanctuary-test:exportDuoLaunch -x :sanctuary:check`, sélection `base204,north208` :
succès en 1 min 1 s ; six tests ciblés, dont la régression du trou profond,
passés. Les contrôles purs précédemment passés ne sont pas répétés à cette étape.
Journal : `build/north208-final-build.log`. Les essais finaux `north208-final` (42) et `north208-final0` (0) passent sur le
JAR final. Offrandes réelles, refus des doublons, interruption à 0/58, reprise
jusqu'à 58 chunks FULL et annonce SGA contrôlés. Serveurs arrêtés proprement.
| Relevé | Graine 42 | Graine 0 |
| --- | --- | --- |
| Sommets / élévation maximale relevée | 5 / 50 blocs | 5 / 44 blocs |
| Colonnes relevées élevées / autres | 183 / 1 775 | 197 / 1 785 |
| Dénivelé moyen à 8 blocs de chaque sommet | 6,6–9,1 blocs | 5,6–6,9 blocs |
| Replats glacés admis | 6 | 5 |
| Glace dans les cuvettes inspectées | 1 972 blocs | 2 000 blocs |
| Glace compacte des formations de rive inspectées | 360 blocs | 236 blocs |
| Échantillons profonds identiques à la 206 | 52 989 | 51 958 |
| Améthyste / faces ouvertes inspectées | 7 731 / 1 928 | 12 494 / 3 567 |
| Cellules de biome vérifiées / incohérences | 1 944 / 0 | 1 944 / 0 |
La neige et les forêts dégagées restent présentes. Cinq igloos et une cave de
soins par île. Manoirs de 544 et 547 pièces, aux mêmes emplacements qu'en 207,
avec trois marches d'accès vérifiées et cinq coffres à table de butin native
chacun. Les comptages sont des relevés locaux ou sur grille, pas un inventaire
exhaustif. Les essais simultanés ne constituent pas un benchmark comparatif.
## Distribution locale
MRpack normal exporté et contrôlé : archive ZIP intacte, JAR strictement identique
au build, profils 207 et 208 Small/Medium/Large présents, aucun module Test ni
monde embarqué. Minecraft 26.3 / Fabric Loader 0.19.5.
Reçu : `build/north208-mrpack-receipt.json`. Copie dans `~/Downloads/`.
SHA-256 : `bf1006efca537996fe4e33750ff08cbf821d2735bc03e5ce517da7fd62922845`.
## Limites
La retouche ne résout pas à elle seule le temps de chargement signalé. Aucun
benchmark comparatif, jugement esthétique global ni essai Windows n'est déduit
des vérifications. La clôture visuelle du Nord revient à la visite du créateur.
## Visite solo
Nouveau monde `Sanctuary-North-208-42` dans
`build/worldgen-lab/north208-final-visit/small/42/client/saves/`, copié depuis
l'essai final arrêté. Vue 32 chunks, simulation 5, créatif en vol et commandes.
Position initiale : **(-389.5, 325, -1060.5)**, face au sommet **(-448, 301, -1008)**.
Replat voisin : **(-457, 278, -1034)** ; second niveau : **(-406, 262, -986)**.
Manoir conservé : **(-27, 252, -1244)**. Anciennes visites préservées.
Le client confirme Vulkan / MoltenVK et `NORTH208_VISIT_OPEN` le 5 octobre
à 03:23:59, en **(-390, 325, -1061)**. Visite ouverte ; aucune inspection graphique
exhaustive ni validation esthétique du créateur n'est déduite de ce lancement.
+68
View File
@@ -0,0 +1,68 @@
# ORIGIN-182 — galerie inférieure et rosace
Suite du retour en jeu sur beta.181, le 30 septembre 2026. Branche
`codex/origin-gallery-beta182`, dans le checkout de développement réutilisé
`rocky-ecology-beta178`. La palette naturelle de l’origine est validée par le
créateur. Les élévations gênent les huit directions ; elles doivent être
placées entre les axes. Essayer une cloche vitrée en rosace et développer
la scène souterraine. L’origine reste en l’air.
La mention « le truc dans les airs » est interprétée ici comme la rosace,
en attendant une éventuelle précision ; l’ISS reste un chantier séparé.
## Contrat du nouveau monde
Nouveau preset facultatif `sanctuary_test:gallery_v1`, profil `gallery`,
graine 42. Les profils précédents et la génération normale restent disponibles
avec leur génération propre. Aucun ancien monde, chunk ou format de sauvegarde
n’est modifié. Aucune expansion ni dimension n’est activée par ce prototype.
La galerie sélectionne une cavité centrale sous X=0/Z=0 par un échantillonnage
borné du champ de densité existant. Deux chambres voisines forment une boucle
avec elle ; les passages suivent des failles inclinées, les sols ondulent et
les plafonds sont voûtés. Roche dominante, calcite par veines, mousse ponctuelle,
quelques reliefs de tuf. Pas de murs rectangulaires plaqués sur toute la caverne.
Un socle d’obsidienne central et deux montants sombres interrompus donnent un
premier emplacement au portail inférieur. C’est une scène architecturale :
ni portail actif, ni recette d’allumage ou téléportation ne sont implémentés.
L’origine conserve la palette, le sol à huit directions et le bloc en
(0,320,0), lumineux et monochrome. Une cloche de verre clair et blanc avec
huit nervures de cuivre patiné remplace les trois élévations. Les supports
sont entre les axes ; huit ouvertures basses conservent vues et passages.
L’ISS, les huit salles d’ancres et les trois secteurs de gemmes ne sont pas
ajoutés dans ce lot.
Les deux lieux sont posés par chunk à la génération, sans ticker, sans
recherche globale d’eau et sans journal de progression. Le plan souterrain
est calculé une fois pour la source de biomes puis réutilisé. Une sauvegarde
recharge les blocs, elle ne reconstruit pas les lieux.
## Vérifications
Compilation et export du lanceur réussis. Monde neuf `solo182a/gallery/42` :
contrôles de la beta.180 conservés (567 échantillons de densité, trois cerisiers,
bassins de 1 232 et 1 221 blocs, cinq spawners et quatre caches avec les gemmes).
Zéro région d’hydrologie calculée.
La galerie contient 1 558 colonnes sculptées ; 1 514 surfaces praticables
appartiennent au même réseau, connecté par marches d’un bloc maximum.
Les trois centres de salle sont en (0,175,0), (-34,169,-26), (-38,146,24).
Le socle porte l’obsidienne en (0,177,0). La rosace compte 1 841 blocs avec
le fragment rocheux : huit axes libres à hauteur du joueur et noyau lumineux
sans relais activé. Rapport local `build/gallery182-quick-result.json`.
Arrêt du serveur de préparation et sauvegarde terminés proprement.
Solo neuf préparé sous `visite182/gallery/42`, `Sanctuary-Gallery-182-Solo`,
vue 32, créatif et commandes, première vue sur la galerie.
Visites : galerie `/tp 0.5 177 7.5 180 0` ; rosace
`/tp 0.5 319 5.5 180 0`. Rendu et proportions à juger en jeu sur la graine 42 ;
aucune autre graine ni capture du rendu n’est revendiquée.
Suite générale `check build assemblePack assembleTestPack` réussie en 8 min 1 s,
265/265 GameTests ; journal `build/gallery182-check-build.log`.
Entrée dans le solo confirmée depuis par le créateur. Le journal
`build/gallery182-solo.log` enregistre KokaLab connecté le 30 septembre à
02:25:12, vue 32 chunks. Son retour valide la palette, la rosace et les étangs ;
la correction du portail et les lieux manquants sont suivis dans
[DISCOVERY-183](island-discovery-beta183.md).
+3 -1
View File
@@ -50,7 +50,9 @@ Compilation et export du lanceur réussis. Le solo neuf
vue 32 chunks. Approche à pied pour la visite : `/tp 0.5 319 5.5 180 0`.
L’appréciation esthétique reste à faire en jeu ; aucune capture du rendu
n’est revendiquée. Seule la graine 42 est validée dans cette itération.
Suite générale `check build assemblePack assembleTestPack` encore en cours.
Suite générale `check build assemblePack assembleTestPack` réussie en
12 min 53 s, journal `build/origin181-check-build.log` dans le checkout
`storyquest-beta173`. Contrôles et assemblages terminés avant la suite beta.182.
Retour en jeu du créateur : palette et caractère naturel validés. Les trois
élévations empiètent sur les directions ; prochaine variante avec supports
+97
View File
@@ -0,0 +1,97 @@
# PAUSE-235 — Aventure et Communauté côte à côte
Branche d'essai `codex/pause-columns-beta235`, base beta.234, commit `f9c2ce8`,
Minecraft 26.3. Le rendu reste à apprécier par le créateur.
## Disposition et réversibilité
Avant Atlas, Aventure et Communauté occupent deux colonnes au même niveau :
Discovery, Progression et Story à gauche ; Habitant, Faction et Battle à droite.
Partie / Game suit juste dessous avec Options, World Options et la sortie
native. L'ensemble est centré verticalement dans le corps de Pause, avec de
l'espace sous Game ; Reprendre la partie reste dans le pied de page.
Sans Atlas, ce bloc est centré entre Gazette à gauche et Notice Board à droite.
Avec Atlas, une seule colonne étroite est serrée à gauche : Communauté, puis
Aventure, puis Partie / Game, selon l'ordre confirmé par le créateur. La carte
garde la région centrale et les deux fils communautaires restent à droite.
Le bloc complet reste centré verticalement. La largeur minimale des boutons
de navigation tient compte des libellés localisés et de leur marge native.
Aux petites hauteurs, boutons et espacements se compactent. Tab suit l'ordre
visuel : par rangée de gauche à droite avant Atlas, puis de haut en bas avec
Atlas. Les libellés FR/EN existants sont réutilisés.
Le changement de disposition et les assertions correspondantes sont isolés
dans le commit `a7bdfe6`, séparé de la livraison et de ses métadonnées. La branche
`codex/story-beta234` conserve la disposition précédente. Un retour s'effectue
avec `git revert a7bdfe6` ; une éventuelle nouvelle
livraison doit prendre le numéro beta suivant, sans diminuer le compteur.
L'application inverse du patch a été vérifiée avec `git apply --reverse --check`,
sans modifier les fichiers de travail.
Ce ticket ne change ni génération, sauvegarde, données communautaires, protocole,
conditions de progression ou contenus Story. Aucune installation personnelle
ou publication n'est demandée.
## Vérifications
```sh
./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true -PsanctuaryPause233ClientTests=true -PsanctuaryClientGraphicsBackend=vulkan
./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true -PsanctuaryStory234ClientTests=true -PsanctuaryClientGraphicsBackend=vulkan
./gradlew check build assemblePack -PsanctuaryFocusedTests=menus -PsanctuaryAtlasOnly=true
```
Le parcours Pause final réussit en 1 min 22 s (`PAUSE233_PASS`), dans un monde
plat neuf de développement, Survie sans commandes. FR/EN, GUI 2/3/4, fenêtre
1280 × 960, avant et après Atlas : six actions Sanctuary, alignement et absence
de chevauchement, largeur des libellés avec la marge native, ordre de Tab et
Game sous les groupes, avec de l'espace avant le pied. Le test attend désormais
un créneau de requête communautaire pour son amorçage et envoie le code de
raccourci natif de Tab, requis par Minecraft 26.3.
Le parcours communautaire existant passe également : publication et photo,
retours des sélecteurs, brouillons, édition d'une ancienne catégorie, inventaire
réel conservé et aucun changement du fichier communautaire pendant les lectures.
La configuration temporaire est restaurée à la fin du banc.
Log : `build/pause235-client-vulkan-final.log`. 38 captures finales copiées dans
`build/pause235-screenshots/`. Captures inspectées : sans Atlas FR/4, avec Atlas
FR/2 et EN/4. Vulkan confirmé : MoltenVK 1.4.2 sur Apple M1.
Le parcours Story final réussit en 29 s (`STORY234_PASS`), avec les mêmes
langues, GUI et états Atlas. Accès depuis les deux dispositions de Pause,
100 entrées désactivées, recherche/filtres, saisie continue et focus, molette,
redimensionnement à 1344 × 1008 et retours Échap / Terminé vérifiés. Le record
de progression serveur ne change pas. Log :
`build/pause235-story-client-vulkan-final.log` ; 21 captures copiées dans
`build/pause235-story-screenshots/`.
Aux GUI étroits, les longs libellés natifs des options/sortie et les titres des
fils gardent leur défilement ou découpage existant ; les boutons de navigation
Sanctuary montrent leur libellé entier. Les infobulles des actions Game sont
conservées. Aucun essai OpenGL, Windows ou monde personnel n'est revendiqué.
Le contrôle `check build assemblePack` réussit en 3 min 1 s : quatre GameTests
requis et contrôles purs du dépôt, dont les quatre contrôles communautaires
fichier/photos/demandes/recherche. Log : `build/pause235-check-build-pack.log`.
Le banc menus conserve sa sélection Atlas existante ; le conflit de générateur
sur le chemin natif par défaut, documenté en beta.232, reste hors de ce ticket.
## Livraison locale
`mod_version`, `pack_version` et `packwiz/pack.toml` sont alignés sur beta.235.
Le commit de livraison conserve ces métadonnées et cette documentation séparées
du commit de disposition.
Export [Sanctuary-beta.235.mrpack](../build/Sanctuary-beta.235.mrpack),
12 776 222 octets : intégrité ZIP, Minecraft 26.3 et Fabric Loader 0.19.5,
un seul JAR Sanctuary embarqué, identique au JAR construit, sans monde ni module
de test. Les 3 303 fichiers d'assets, données et resourcepacks sont identiques
à beta.234, traductions incluses. Story reste dans le JAR de production et les
classes des bancs client en sont absentes. Reçu :
`build/pause235-mrpack-receipt.json`.
- JAR : `aad94732c749161d775ee634bdd85de70de511ef875c6c00fa167d230d0d600b`.
- MRpack : `5f1bd18aa8a4145b7e708da0abfff22068365847dddbc95ae2b490b88bbb305e`.
Aucune publication distante, modification du canal packwiz, synchronisation
Prism ou ouverture d'un monde personnel effectuée.
+86
View File
@@ -0,0 +1,86 @@
# PAUSE-233 — navigation centrée et rédaction communautaire
Branche `codex/pause-community-beta233`, base beta.232, Minecraft 26.3.
## Résultat et compatibilité
Avec ou sans Atlas, les boutons gardent les mêmes groupes et le même ordre :
- Communauté : Habitant, Faction et Battle en haut de la colonne.
- Aventure : Discovery et Progression centrés verticalement dans l'écran.
- Partie : Options, World Options et Save and Quit en bas.
Sans carte, cette colonne est centrée horizontalement entre Gazette à gauche
et Notice Board à droite. Avec carte, elle reste à gauche, carte au centre et
les deux fils communautaires à droite. L'ordre clavier suit l'ordre visuel.
Les boutons deviennent plus compacts sur les petites hauteurs GUI pour conserver
les titres et l'espacement entre groupes. La petite barre sous les boutons
Communauté est supprimée dans les deux dispositions. En-tête et reprise en pied
conservés.
Le formulaire Notice Board ne propose plus Information/Project/Request/Event.
Toutes les notices ont la même présentation, y compris les anciennes catégories.
Les demandes et récompenses restent facultatives et descriptives : après le
texte viennent Request and rewards, son résumé, puis Publish. Le formulaire
Gazette place la photo et Choose a screenshot en premier, avant le titre,
puis le texte et Publish.
Photo obligatoire, brouillons, édition, retours des sélecteurs, suivis et
validations serveur restent actifs.
Le contrat fichier/MariaDB et le protocole ne changent pas. Les nouvelles notices
gardent la valeur compatible `info` ; éditer une ancienne annonce conserve sa
catégorie enregistrée sans l'afficher. La lecture n'entraîne aucune réécriture
des posts. Aucune migration, génération ou opération d'inventaire n'est ajoutée.
Les anciennes traductions de catégories restent disponibles pour les données
historiques. Titres ajoutés en français/anglais : Communauté/Community,
Aventure/Adventure et Partie/Game ; les autres libellés existent déjà.
## Vérifications et livraison
`./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true
-PsanctuaryPause233ClientTests=true -PsanctuaryClientGraphicsBackend=vulkan`
Réussite en 47 s (`PAUSE233_PASS`), après suppression de la barre sous Communauté.
Monde plat de développement, Survie sans Allow Commands, stockage fichier isolé.
- FR/EN, GUI 2/3/4, fenêtre 1280×960, avant et après Atlas : même ordre des
actions et des groupes, titres sans chevauchement, paire Discovery/Progression
centrée verticalement, navigation et options séparées.
- Ordre titre → texte → demande et résumé → publication, ou photo et sélecteur
→ titre → texte → publication ; aucune catégorie visible. Défilement du formulaire sur GUI
étroit vérifié. 38 captures dans `build/pause233-screenshots/`.
- Retours réels des sélecteurs : texte conservé, 128 bûches demandées et
récompense personnalisée publiées ; les 17 bûches et 3 diamants d'inventaire
réel restent présents. Photo toujours obligatoire, article et photo relus
depuis un nouveau lecteur du stockage fichier après publication.
- Ancienne catégorie `event` conservée lors de l'édition. Lecture des posts,
redimensionnements et changements de langue n'altèrent aucun octet du fichier
communautaire. Configuration du banc restaurée à la fin.
- Captures inspectées : pause verrouillée FR/2 et EN/4, pause déverrouillée FR/2,
notice configurée, Gazette avec photo assignée et bas du formulaire Notice Board
EN/4. Notices anciennes et nouvelles ont le même cadre et ne montrent que leur état.
Log client final : `build/pause233-client-vulkan-titled.log`. Aucun essai OpenGL ou Windows
et aucune migration MariaDB ne sont revendiqués ; le code serveur est conservé.
`./gradlew check build assemblePack -PsanctuaryFocusedTests=menus
-PsanctuaryAtlasOnly=true`
Réussite en 2 min 39 s : quatre GameTests requis, contrôles purs communautaires
(`COMMUNITY154_FILE_PASS`, `COMMUNITY157_PHOTOS_PASS`, `COMMUNITY158_TASKS_PASS`,
`COMMUNITY159_SEARCH_PASS`), build et assemblage du pack.
Log : `build/pause233-check-build-pack-final.log`.
Ce contrôle utilise le mode existant du banc pour les menus. Le chemin natif par
défaut présente toujours le conflit de générateur documenté en beta.232 ; cette
livraison ne revendique pas une nouvelle suite complète de génération.
Export local `build/Sanctuary-beta.233.mrpack` vérifié : intégrité ZIP, versions
Minecraft 26.3/Fabric Loader 0.19.5, un seul JAR Sanctuary embarqué, exactement
identique au JAR construit, sans module de test ni monde. Les 3 146 fichiers
de données et assets hors traductions sont identiques à beta.232 ; seules les
trois traductions de titres de groupes sont ajoutées en FR/EN, sans changer les
libellés existants. Reçu : `build/pause233-mrpack-receipt.json`.
- JAR : `23a148c197126ede552865f9847ce381700884d5ff087469a13e36540e8f23f9`.
- MRpack : `d95aeeca5f255db4444a22879f465477c0c6a2a111dd4e1c777b20944a283e2b`.
Livraison locale beta.233 ; aucune installation personnelle, publication
distante, ouverture d'un monde personnel ou mise à jour du canal packwiz.
+115
View File
@@ -0,0 +1,115 @@
# WG-215 — Relais régionaux visibles
Branche `codex/regional-relays-beta215`, depuis beta.214 (`b82ab37`).
## Contrat
Retirer le village Far West des nouvelles générations. Au Sud et au Nord,
remplacer le petit marqueur de relais par un monument compact, massif et
surélevé, apparenté aux ancres de Sanctuary, avec des matériaux régionaux.
La rosace allumée du relais reçoit entièrement la couleur de sa direction ;
le bloc originel conserve sa progression indépendante par huit gemmes.
Agrandir modérément la pyramide extérieure, sans changer le labyrinthe,
les coffres ou les pièges validés.
Nouveaux profils 215 uniquement ; les profils historiques gardent leur recette.
Aucun ancien monde ou chunk n’est retouché, aucune conversion de journal.
Les textures communes d’ancre changent d’aspect, sans changement de sauvegarde.
Essais autorisés sur des mondes jetables neufs : activation réelle des ancres
Nord/Sud, interruption et reprise. Nouvelle visite Vulkan 32 chunks et MRpack
local ; aucun canal public ou Prism modifié. Graines prévues : 42 et 0.
## État
Implémenté ; essais natifs et assemblage final réussis. Nouvelle visite ouverte.
Le rendu reste à apprécier en jeu.
## Réalisation
`RegionalRelay215` ajuste un socle octogonal de 13 blocs de large à une surface
rocheuse mesurée (feuilles et eau exclues). Recherche limitée à 64 blocs autour
du relais, dénivelé maximal de quatre blocs sous le socle, supports courts.
L’ancre est cinq blocs au-dessus de la base, accessible par un escalier de
largeur trois ; deux pylônes massifs encadrent la direction extérieure.
Améthyste sous le verre, tuff sculpté, éclairages limités. Au Sud, terracotta
de la strate locale et verre rouge ; au Nord, diorite, calcite, glace compacte
et verre bleu clair. Pas de toit masquant le bloc.
Plan immuable indexé par chunk, réservé avant végétation, compris dans les
chunks préparés avant l’annonce SGA. Le manoir du Nord évite cette emprise.
Le paiement du relais se réfère à la position surélevée. Aucun calcul permanent
ou nouveau format de sauvegarde. Les autres directions conservent leur recette.
Le village Far West est limité à son ancien profil 214.
Pyramide 215 : base 31 × 31 au lieu de 23 × 23, sommet quatre blocs plus haut,
même terracotta locale et entrée prolongée. Le gabarit souterrain, les dix
coffres et les huit pièges (24 TNT) sont conservés. La recherche contrôle toute
la nouvelle base ; une courte fondation raccorde la coque à la roche.
Les huit textures de relais allumés colorent toutes les gemmes d’une seule
teinte directionnelle, échantillonnée au cœur de chaque gemme de l’illustration.
Logo central, transparence et état éteint conservés. Les 514 ressources du
bloc originel (textures/modèles) sont comparées à l’artefact 214 ; sa progression
par gemmes reste indépendante.
## Essais natifs
Mondes jetables `south215-verified` (graine 42) et `north215-verified0` (0),
île principale Small 512, expansion de 1024. Paiement de l’ancre racine, rejet
d’un mauvais paiement et d’un doublon, interruption après réservation puis
reprise réussis. Aucun ancien monde utilisé.
| Relevé | Sud — 42 | Nord — 0 |
| --- | --- | --- |
| Ancre surélevée | 128, 258, 1224 | 352, 211, -1252 |
| Chunks du monument | 4 | 4 |
| Blocs comparés au plan | 2326 | 2390 |
| Profondeur maximale des supports | 6 | 8 |
| Marches d’approche | 5 | 14 |
| Chunks préparés | 67 | 58 |
Tous les blocs du monument, y compris les dégagements et les marches,
correspondent aux chunks produits. Le paiement incomplet sur la nouvelle
position est refusé avec `required`, confirmant que le relais est reconnu
(et non `invalid`). Reconstruction du cache identique après reprise.
Le village 214 n’est ni actif ni planifié dans ces profils.
Au Sud, pyramide en (32, 249, 848), largeur 31, dix coffres, dix piles
enchantées et 24 TNT vérifiées. Au Nord, le manoir reste planifié, séparé
du monument (origine 364, 255, −635). Pas de nouvelle passe de relief.
Ces essais sont fonctionnels : aucun benchmark, test Windows ou jugement
esthétique n’est déduit de leurs temps de génération.
## Vérifications et livraison locale
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south213,relays215 -PsanctuaryAtlasOnly=true`
réussi en 3 min 56 s : contrôles purs et **10 GameTests ciblés**, journal
`build/relays215-final-build.log`. La suite historique complète des GameTests
n’est pas revendiquée. Tests de placement Nord/Sud sur graines directes 0 et 42,
accès à pied, supports bornés, palette et reconstruction déterministe ;
contrôle des anciens profils et de l’intérieur de la pyramide.
La première sélection des teintes pouvait choisir le même reflet clair pour
deux secteurs : corrigée par un échantillonnage des huit cœurs de gemmes.
Contrôle final : huit images distinctes, 103 pixels colorés chacune,
logo central et alpha préservés (`build/relays215-textures.log`). Les trois
fichiers de bruit de l’île principale sont identiques à 214.
MRpack normal : `/Users/koka/Downloads/Sanctuary-beta.215.mrpack`.
Intégrité ZIP, métadonnées, JAR exact, modèles et textures corrigées, trois tailles
et profils historiques contrôlés ; aucun module Test ou monde inclus.
SHA-256 : `8fb19d272fa56b47ac15e79c4ecdba8fcff784280bef0961c8c68c592aa3ba02`.
Reçu : `build/relays215-mrpack-receipt.json`. Aucun tag, canal public ou Prism
modifié. Une graine dont le terrain ne permet aucun site dans la recherche
bornée peut encore refuser le monument ; les quatre placements du test et
les deux expansions réelles ci-dessus passent.
## Visite
Solo neuf `Sanctuary-South-215-42`, ouvert le 5 octobre 2026 à **07:49:47 CEST**,
confirmé par `SOUTH215_VISIT_OPEN`. Départ (150.5, 269, 1200.5), face au relais
(128, 258, 1224). Pyramide en (32, 249, 848). Créatif en vol, commandes,
32 chunks / simulation 5. Backend Vulkan (MoltenVK 1.4.2) confirmé dans
`build/south215-launch.log` ; aucun essai OpenGL. Ancienne visite 214 arrêtée
proprement et conservée. Le joueur reste juge du rendu des monuments.
+61
View File
@@ -0,0 +1,61 @@
# WG-RESTORE-191 — revenir avant les plateaux
Branche `codex/restore-relief-beta191`, Minecraft 26.3, graine de visite 42.
Nouveau profil `original`, preset `sanctuary_test:pre_terraces_v1`.
## Contrat
Le retour beta.190 rejette toujours le relief et les affleurements ajoutés depuis
les plateaux. Restaurer exactement le champ de densité **beta.188**, avant les
terrasses beta.189 et les épaules beta.190. Retirer leurs passes d’affleurements
et leur exclusion d’arbres sur ces affleurements. La géologie d’origine retrouve
sa responsabilité : pierre, strates, gisements, cavités et pointes existantes.
Conserver les corrections indépendantes appréciées : ancres au sol, berges,
cascade large, galerie éclairée et coffres de fer enchanté dans les ruines.
Cela restaure le relief et la géologie de base, pas tous les blocs d’un monde
beta.188 puisque ces aménagements récents restent présents.
L’intention pour la suite est un récif avec creux, cavités et pointes, avec
quelques formations singulières par endroits. Aucun nouveau lissage, plateau
ni déformation généralisée dans cette remise à plat du travail.
Les variantes 189/190 restent des références conservées, hors de ce nouveau profil.
Nouveaux mondes seulement ; aucune sauvegarde existante modifiée ou régénérée.
## Vérifications
Génération et réouverture natives réussies, graine 42 :
`build/original191a-cold.json` et `build/original191a-warm.json`.
- **134 480 densités identiques** aux paramètres enregistrés de beta.188, de
Y=0 à Y=632 sur l’île et ses îlots ; aucun remappage de hauteur activé.
- Passes d’affleurements 189/190 court-circuitées dans ce profil. Leur masque
est inactif sur les 1 681 colonnes contrôlées ; la règle de géologie d’origine
et les plantations natives reprennent la surface hors des aménagements réservés.
- Comparaison au commit beta.188 `658aaf8` : corps du calcul de densité, paramètres
de bruit, îlots aériens et règle de géologie identiques. Preuve locale :
`build/original191-baseline-receipt.json`.
- Huit ancres, 49 cartes et cadres du palais, salle inférieure et éclairage,
quatre ruines avec coffres enchantés, donjon, gemmes et soufre contrôlés.
- Cascade de cinq blocs de large conservée, chenal de 4–5 blocs et huit blocs
de roche retirés ; aucune nouvelle déformation de montagne pour la produire.
Zéro tronc dans les colonnes contrôlées des bassins et berges.
Démarrage natif : 12,281 s à froid et 0,738 s à chaud ; avec tous les contrôles
et le remplissage des cartes : 79,283 s / 22,798 s. Zéro région d’hydrologie.
Ces contrôles de laboratoire ne sont pas lancés au démarrage du solo.
`./gradlew check build assemblePack assembleTestPack` réussi en **7 min 40 s**,
**265 GameTests réussis**. Le JAR est identique aux classes et ressources compilées
et à sa copie distribuée dans le pack de test : `build/original191-pack-receipt.json`.
Aucune publication ni modification de l’installation Prism. Le client Vulkan est lancé avec la nouvelle
sauvegarde `Sanctuary-Original-Relief-191-Solo`, run `visite191`, profil `original`,
vue 32 et simulation 12, spectateur, commandes autorisées, position préparée
(94,316,153) face au relief. Connexion confirmée à **21:46:39**, vue 32 et simulation 12 ; Vulkan confirmé.
Les cartes et l’état initial des ancres ont été relus dans cette copie neuve.
Les sauvegardes 188/189/190 restent conservées.
Le créateur a confirmé l’ouverture ; la connexion est vérifiée dans
`build/original191-solo.log`. Cette confirmation porte sur l’entrée dans le solo,
pas encore sur l’appréciation esthétique du terrain restauré.
+143
View File
@@ -0,0 +1,143 @@
# EXP-199 — affiner les expansions et les raccorder au laboratoire
Branche `codex/runtime-expansions-beta199`, depuis beta.198. Retour R014.
Implémentation et validation locales ; aucune publication du canal packwiz ni mise à jour de Prism.
## Contrat retenu
Réutiliser `ExpansionJournal`, `ExpansionRuntime`, les contrôles d'occupation,
les contextes de bruit natifs et les biomes d'expansion existants. Les ancres
actuelles du laboratoire doivent désormais demander une vraie expansion.
Recherche automatique sur 360°, priorité à la proximité du parent parmi les
sites admissibles, une région immuable par relais, et un nouveau relais sur
chaque région prête. Relief fin : surface large et ondulée, quelques plateaux
souples, volumes amincis en conservant les cavités du bruit 3D.
Les lectures d'admission et la préparation native sont échelonnées entre les
ticks. Annonce SGA aux joueurs seulement après les chunks FULL et le relais.
Les doubles activations ne créent ni second continent ni double prélèvement.
La sauvegarde reprend une région réservée après interruption.
## Contrat de nouveaux mondes
Les profils 196–198 gardent leurs paramètres et leurs ancres de démonstration.
Les nouveaux profils 199 initialisent un journal d'expansions propre. Aucun
ancien monde n'est migré, aucun chunk existant régénéré, aucun ancien format
réécrit. Première admission limitée aux régions réellement vierges ; même du
vide déjà généré reste protégé. Cette contrainte peut éloigner une expansion
si le joueur a déjà exploré les alentours ; ce n'est pas une promesse de
contact bord à bord. La réutilisation du vide certifié reste le mécanisme
historique distinct, à ne pas activer implicitement dans une partie.
## Ciel et performance
Rotation stellaire : sept journées Minecraft, sur l'horloge du monde faisant
autorité ; conserver la même transformation pour la visée et les constellations.
Les saccades sont également signalées à l'arrêt, y compris shader Sanctuary désactivé (confirmation du créateur). Aucune cause n'est attribuée
au worldgen sans mesure ; préserver cette enquête séparément du réglage des
expansions. Les débordements de mares restent consignés sans nouvelle refonte.
## Première tranche jouable
Le relais demande les mêmes huit offrandes distinctes que le laboratoire. Le
joueur reste à proximité, offrande en main, pendant la recherche. Les matériaux
ne sont retirés qu'après réservation durable. Une seule préparation est active
à la fois ; chaque relais ouvre une région de diamètre nominal 256 blocs, avec
un relais de continuation. Le climat suit la couleur du relais d'origine ; la
position réelle est choisie automatiquement parmi 64 angles, par distances
croissantes sur la grille de chunks. Le relief réutilise la densité 3D historique,
comprimée verticalement autour de Y=220 et déformée par son bruit cohérent.
Les biomes naturels décorent ces nappes. Les villages et forteresses vanilla ne
sont pas réactivés par l'ajout de ces biomes à la palette : leurs structures
seront une tranche distincte. Les structures et reliefs de l'île centrale sont
conservés. Pour Small/42, une recherche locale plus précise peut retrouver les
sols d'ancres manqués par la grille historique ; les réservations d'eau suivent
alors leurs emprises réelles avec marge au lieu d'exclure un secteur entier.
Le moteur conserve son journal et sa file native, avec un adaptateur réservé aux
profils 199. Admission : 32 lectures asynchrones au maximum par lot, contrôle des
chunks chargés et des sauvegardes concurrentes, mémorisation des refus
pour éliminer les candidats qui recouvrent un chunk déjà trouvé occupé, puis réservation et publication
sur le même tour serveur. Le relais suivant est placé après les chunks FULL ;
l'annonce SGA possède une infobulle lisible donnant ses coordonnées.
Limites : pas de régénération du vide déjà exploré, pas de choix de direction,
pas encore de variation du prix/taille pour les relais successifs. La limite
historique reste de 64 régions, Sanctuary incluse. Le journal et l'inventaire
joueur sont deux fichiers Minecraft distincts : la protection contre le double
clic ne constitue pas une transaction atomique entre ces fichiers lors d'une
coupure brutale au milieu d'une sauvegarde.
## Périmètre de validation
Placement proche sur tous les angles et refus des emprises occupées, densités
bornées et nappes fines, horloge stellaire cyclique, activation réelle, deuxième
relais, double interaction, interruption/reprise et notification après FULL.
`check build`, assemblages et essai client Vulkan avant livraison locale.
## Relevés de validation
- Compilation et assemblages : `check build assemblePack assembleTestPack`,
avec les suites natives `operator,realtime`, réussis (7 GameTests et contrôles
purs). La vérification du placement couvre 9 couples graine/taille : 0, 42 et
4736390610738281858 × Small/Medium/Large, les huit secteurs, l'ordre de distance,
les conflits et la réouverture du journal.
Dernier passage complet : `build/expansion199-check-build-delivery.log`,
réussi en 3 min 40 s. Compilation finale des tests client réussie également.
- Nouveau Small, graine 42, 2 Gio : serveur prêt vers 14,2 s ; première expansion
au centre (368, -368), relais Y=231, après 418 chunks FULL. Le deuxième relais
réserve son enfant environ 11 s après l'annonce du premier. L'arrêt volontaire
a lieu avec cet enfant encore réservé. Cette durée inclut les essais et n'est
pas le temps normal de création d'un monde.
- Journaux finaux : `build/expansion199-check-build-final.log` et
`build/worldgen-lab/expansion199-native-final/small/42/`. Les premiers essais
interrompus restent conservés et ne sont pas des validations.
- Réouverture du même Small/42 : enfant repris, 418 chunks FULL, relais
(912, 236, -368), une seule annonce pour cet enfant et aucune répétition de
celle du parent. Sur 81 colonnes échantillonnées, 1380 blocs non vides, entre
Y=191 et Y=275 (végétation comprise) : ce relevé local ne mesure pas le volume
total de toutes les expansions.
- Client Vulkan, Small/42 : arrivée sur l'île, synchronisation native des étoiles
et pause de l'horloge, vraie interaction du joueur avec le relais, double clic
sans double prélèvement. Un bloc d'or placé dans le premier candidat reste
intact et force l'admission d'un autre emplacement. Les interfaces FR/EN,
trois tailles, profils historiques et aller-retour disque passent également.
- Deux essais client consécutifs terminent l'expansion puis sauvegardent et
ferment normalement (`build/expansion199-client-pass-a.log` et
`build/expansion199-client.log`). Le tout premier essai avait réussi les
assertions puis rencontré une exception dans `ChunkMap.tick`, lors du suivi
des entités. Cause non isolée : un contrôle de réentrance et 100 ticks
d'observation supplémentaires n'ont pas reproduit le défaut. Ce résultat
n'est pas un correctif prouvé du crash initial. Pas d'essai direct Windows.
### Saccades : capture locale, cause non isolée
Première capture client macOS Vulkan, Small/42, vue 8 chunks, shader désactivé, joueur immobile :
1241 images relevées, médiane 31,15 ms (limitation de cadence de l'environnement
de test), P95 33,12 ms, P99 33,71 ms, maximum 98,01 ms, 7 images au-delà de 50 ms.
258 sections ont encore été compilées pendant la capture. Le JFR contient 4152
échantillons de workers dans la génération, et des pauses GC jusqu'à 88,45 ms.
Le joueur immobile ne signifiait donc pas que le chargement avait terminé.
Ce relevé n'isole pas les saccades d'une partie complètement stabilisée, et ne
prouve pas leur cause chez le créateur. Le shader n'est pas nécessaire pour
reproduire quelques images longues dans cet environnement. Aucun correctif
général des saccades n'est revendiqué dans cette livraison.
Mesures ignorées par Git :
`build/expansion199-stationary-first/stationary.json` et `stationary.jfr`.
Les captures suivantes restent sous
`mods/sanctuary/build/run/clientGameTest/diagnostics/expansion199/`.
Pas de nouvelle campagne de screenshots.
## Livraison locale
`Sanctuary-Test-beta.199.mrpack`, 12 322 965 octets, copié dans
`/Users/koka/Downloads/` avec `Sanctuary-Test-beta.199-Guide.txt`.
SHA-256 : `fd2ebe4f43bf0d455377a2f456106165ff5e3519e5c3dce4126818c03f4ae44f`.
Intégrité ZIP, manifeste Minecraft 26.3/Fabric Loader 0.19.5, dépendances externes,
JAR intégrés comparés aux classes compilées et anciennes ressources vérifiés.
Les 142 ressources historiques de génération restent identiques à beta.198 ;
le preset public vise désormais 199. Reçu : `build/expansion199-artifact.json`.
Le canal packwiz et l'installation Prism n'ont pas été modifiés.
+126
View File
@@ -0,0 +1,126 @@
# WG-SHARE-196 — laboratoire partageable, trois tailles
Branche `codex/lab-mrpack-sizes-beta196`, depuis beta.195, Minecraft 26.3,
Fabric Loader 0.19.5, Java 25. Demande : donner le dernier labo à un ami sous
forme de `.mrpack`, avec Small, Medium et Large, puis diagnostiquer la lenteur.
## Parcours et périmètre
Dans le pack **Sanctuary Test**, Solo → Créer un monde → Monde → type
**Sanctuary** → **Personnaliser** propose Small (512), Medium (724, défaut),
Large (1024). Les types vanilla restent disponibles. Le module Test fournit le
preset public ; le pack ordinaire sans ce module conserve sa génération.
L’interface ne propose plus les anciens laboratoires. Annuler et Échap ne
modifient rien ; la taille est conservée lors du rechargement des registres et
dans les réglages enregistrés. Libellés FR/EN.
Les nouveaux réglages sont `sanctuary_test:shared_island196_small`, `medium`,
`large`. Les anciens codecs et presets restent présents. Aucun monde existant
n’a été migré, modifié ou régénéré. Le preset caché `production_reference196`
conserve le témoin de l’ancienne génération pour le lanceur scientifique.
Le terrain reprend le profil `coherent` : rayon natif selon la capacité, sans
étirer les voxels. Les bornes des biomes, l’écartement des récifs, la recherche
des bassins et ancres, les secteurs de gemmes et la sortie du donjon suivent
la taille. Les pièces conservent leurs dimensions physiques. Atlas de 25/49/81
cartes ; rosace à Y=640 et palais vers Y=1280 dans la dimension haute de 1600.
Aucune nouvelle direction esthétique ni campagne de screenshots.
En Small/Large, la réservation des ancres tient compte de la hauteur : un
refuge sec peut surplomber une autre installation, sans empiéter sur son
volume. C’est nécessaire pour que le donjon ne condamne pas tout un secteur
d’une petite île. Les poches d’eau naturelles restent conditionnées à un creux
fermé : l’absence d’une poche supplémentaire ne crée pas un bassin artificiel.
Les grands bassins souterrains et les étangs de surface sont vérifiés séparément.
La graine 0 en Large a révélé une poche native de dripstone dans le sol d’un
couloir, puis des pointes sèches dans un recoin immergé d’un étang. Les nouveaux
profils protègent les sols de circulation via un index par colonne et toutes
les cellules d’eau retenues, y compris celles sous un surplomb. Les protections
historiques restent utilisées pour les anciens profils.
## Diagnostic du chargement beta.195
Le créateur a quitté la visite puis lancé un nouveau monde Large depuis le
menu. Les journaux identifient la graine `3466058668915588406` et **l’ancien
générateur**, pas le labo `coherent`. Du démarrage du serveur à la sélection
du spawn : 18:09:26 → 18:11:05, soit environ 99 secondes.
Les chronos internes indiquent notamment l’hydrologie régionale (plusieurs
millions de sondes par région), Transit24 (23,4 s), le sanctuaire minéral
(33,7 s), Heritage24 (15,5 s) et les anciennes expéditions. Certains chronos
s’imbriquent : ne pas les additionner.
Un JFR de 43 secondes a capturé ensuite la préparation des chunks de cette
ancienne génération : 2509 échantillons Java, nombreuses piles TransitPlan21
et HeritagePlan19, bruit natif et allocations de streams/maps. Les huit GC
mesurés totalisent environ 2,16 s (pas uniquement des pauses du jeu). Le nouveau
Voronoï n’apparaît pas dans ce relevé, car ce générateur ne l’utilise pas.
Un second relevé intermédiaire sur **Small, graine 0**, avant les diagnostics détaillés,
contient 1578 échantillons CPU : 1151 (72,9 %) incluent les bruits natifs,
118 (7,5 %) les recherches d’eau et 11 (0,7 %) l’érosion Erosion192, qui contient
les joints Voronoï locaux. Ces ensembles peuvent se recouvrir ; ce n’est pas
une décomposition additive du temps mural. La piste prioritaire serait de
réduire les évaluations répétées du relief et les sondages de bassins, en
comparant exactement les blocs produits. Cette optimisation n’est pas livrée
ici : le raccordement au bon générateur élimine déjà les anciens planificateurs.
Le lanceur accepte maintenant `--jfr CHEMIN` pour produire des enregistrements
séparés à froid et à chaud. Exemple :
```sh
python3 scripts/worldgen_lab.py verify --profile large --seed 0 \
--run mesure-nouvelle --memory 2048 --jfr build/profils/large.jfr
```
`serverStartedMs` mesure l’arrivée au spawn serveur. `readyForVisitMs` inclut
ensuite les diagnostics qui chargent d’autres chunks, inspectent les structures
et calculent l’atlas. Ne pas présenter cette deuxième durée comme l’attente
normale du joueur. Ces essais ne mesurent pas la fluidité Vulkan à 32 chunks.
Les JFR bruts restent ignorés et ne sont pas intégrés au pack.
## Vérifications et distribution
`./gradlew check build assemblePack assembleTestPack -PsanctuaryFocusedTests=menus`
réussi : suite des contrôles purs, quatre GameTests menus, modules et pack.
Parcours natif client Vulkan final réussi en FR/EN, sans captures : entrée
publique du labo, trois tailles, Annuler/Échap, rechargement des registres,
aller-retour des réglages sur disque et personnalisation vanilla.
Création et réouverture de la graine 0 réussies pour les trois tailles :
| Taille | Diamètre | Spawn à froid | Spawn après réouverture | Froid avec diagnostics | Cartes |
|---|---:|---:|---:|---:|---:|
| Small | 512 | 14.34 s | 0.72 s | 62.0 s | 25 |
| Medium | 724 | 19.86 s | 0.64 s | 120.2 s | 49 |
| Large | 1024 | 23.96 s | 1.26 s | 144.5 s | 81 |
Huit ancres et offres distinctes, donjon et butin, étangs sans cellules perdues,
portail inférieur, palais, soufre, ruines et secteurs de gemmes contrôlés.
Zéro région d’hydrologie lourde dans les six passages. Les chronos ont été pris
avec JFR, parfois pendant d’autres contrôles : **pas un benchmark isolé**, ni
une garantie de chargement graphique à 32 chunks. Les essais antérieurs Small
sans concurrence atteignaient environ 11 s au spawn serveur. Les autres graines
et le matériel de l’ami restent à éprouver.
Les rapports Medium/Large sont dans `shared196f`, Small dans `shared196g`.
Entre les deux, seule la résolution des identifiants de taille a été mise en
cache pour éviter les allocations dans les protections : mêmes chaînes,
capacités, données et algorithmes de génération. Après ce dernier ajustement,
contrôle/construction du module Test et réassemblage réussis ; contrôles du
mod principal déjà passés réutilisés. Une relance redondante de leur suite est
interrompue, sans être comptée comme une seconde réussite complète.
Export final `Sanctuary-Test-beta.196.mrpack`, 12 268 171 octets, copié dans
`/Users/koka/Downloads/`, avec guide séparé. SHA-256 :
`f73db69953641237399d4d3f0210ba0252e1ea45377b5ff57d6e231d67aa5988`.
Archive ZIP et manifeste vérifiés ; classes identiques aux classes construites,
trois capacités dans les ressources, dépendance Fabric API téléchargée et
vérifiée par SHA-512/SHA-1. Aucun monde, log, secret ou réglage personnel inclus.
Demeure et JEI sont imbriqués dans Sanctuary. Export local uniquement, sans
publication du canal packwiz, synchronisation Prism ou envoi à un tiers.
Traces ignorées : `build/shared196-check-build.log`,
`build/shared196-final-assemble.log`, `build/shared196-client-final.log`,
`build/shared196-artifact.json`, `build/worldgen196-profile/` et les rapports
`build/worldgen-lab/shared196{f,g}/.../{cold,warm}.json`.
+114
View File
@@ -0,0 +1,114 @@
# SOLO-232 — réglages et progression en solo
Branche `codex/solo-time-building-vein`, base beta.231, Minecraft 26.3.
## Comportement et contrat de sauvegarde
`/sanctuary time timezone <fuseau IANA>` choisit le fuseau et sa ville solaire
de référence pour ce monde. `timezone auto` reprend le réglage automatique
solo ou la configuration dédiée. Le propriétaire solo peut faire ce choix
sans Allow Commands ; les autres joueurs et le serveur dédié exigent les
droits opérateur. Le statut affiche le fuseau et la commande propose les
identifiants disponibles sans accès réseau.
Le choix persiste dans le champ opaque `reference` du contrat solaire existant,
avec le préfixe `timezone:`. Le schéma 1 et les autres champs restent inchangés.
Les anciennes références restent lisibles. Le changement réancre le calendrier
à son cycle courant, écrit atomiquement avant l'application solaire et ne
change jamais `gameTime`. Le mode Vanilla reste Vanilla. `auto` retire le
préfixe ; une ancienne version reprendrait sa référence configurée au prochain
rechargement. La configuration globale et les autres mondes ne sont pas modifiés.
Seule la commande explicitement exécutée par le joueur change son contrat.
Construction utilise les portées 3 / 3,5 / 4 / 4,5 / 5 / 5,5 / 6 / 7 blocs.
Avec un bloc en main principale ou secondaire, la visée suit cette portée :
un contour hors portée native reste un support de pose. Minage, contenants,
combat, protections, collisions et stock conservent leurs validations propres.
Une pose visible peut être refusée pour ces raisons ordinaires, mais pas par
une portée de construction différente de celle de la visée.
R + clic gauche maintenus terminent le groupe verrouillé, puis sélectionnent
le nouveau bloc regardé et démarrent un nouveau groupe. Chaque groupe conserve
sa durée native, son coût et la validation serveur. Une confirmation serveur
de réussite permet la reprise ; refus, outil cassé ou remplacé, interruption,
menu ou relâchement arrêtent le geste. Un maintien ne rejoue jamais le même
groupe terminé. Aucun groupe n'est lancé sans cible valide.
## Menu pause et butin de l'île
Avant l'achat Atlas, aucun widget World Map ni requête
de carte n'est créé dans le menu pause. Discovery, Progression, Inhabitant,
Faction, Battle, Options, World Options et Save and Quit sont centrés.
Gazette est à gauche des boutons et Notice Board à droite, chacune sur toute
la hauteur du corps du menu. Calendrier et bulletin conservent leurs emplacements.
Après déblocage, la disposition avec carte
et les deux fils à droite revient à la prochaine ouverture du menu.
Les diamants sont retirés lors du premier remplissage
des coffres et wagonnets à coffre situés sur l'île initiale du générateur
Sanctuary, quelle que soit la table de butin (mines natives comprises).
Les expansions, autres dimensions et mondes ordinaires conservent leurs tables.
Les coffres déjà ouverts et les objets déposés manuellement sont conservés.
Les caches non ouvertes de mondes existants suivent cette nouvelle règle à leur
ouverture ; aucune visite ou réécriture de chunks n'a lieu. Aucun minerai ni
profil de génération ne change. La graine n'affecte pas l'exclusion des diamants.
La règle s'applique au générateur courant NoiseBased et à ses trois tailles,
ainsi qu'aux anciens profils Sanctuary. Le filtre intercepte uniquement
`LootTable.fill`, sans changer les tables elles-mêmes ni leurs autres usages.
Les 794 ressources de génération et de butin du JAR beta.231 restent identiques.
La génération demeure 231 ; graines de butin vérifiées : 0, 42, 232, puis
256 tirages de la table native abandoned_mineshaft.
## Livraison et vérifications
Version mod et pack : `beta.232`, Minecraft 26.3, Fabric Loader 0.19.5, Java 25.
Le nouveau message serveur `sanctuary:mining_result` autorise la reprise d'un
groupe terminé ; client et serveur doivent utiliser cette livraison ensemble.
Le client attend aussi la mise à jour du bloc initial avant de recalculer sa
visée, car la confirmation peut arriver avant les blocs détruits.
`./gradlew check build assemblePack -PsanctuaryFocusedTests=realtime,mining,building
-PsanctuaryAtlasOnly=true` réussit en 2 min 36 s : 24 GameTests requis et les
contrôles purs du dépôt passent. Fuseau persistant/idempotent, fuseau invalide
et contrat modifié extérieurement refusés, mode Vanilla et horloge native
préservés ; validations serveur du minage et de la construction conservées.
Log : `build/solo232-check-build-pack.log`.
`./gradlew :sanctuary:runGameTest -PsanctuaryFocusedTests=solo232
-PsanctuaryTestGeneration=13` réussit en 37 s : 2 GameTests requis, remplissage
réel avec le mixin, conservation des diamants déposés et du fer, butin distant
et contexte absent préservés, identification des trois profils courants.
Log : `build/solo232-loot-native.log`.
Les contrôles utilisent les modes existants du banc d'essai. Son chemin par
défaut tente encore de convertir le preset courant NoiseBased en ancien
SanctuaryChunkGenerator et échoue avant les tests. Ce ticket ne corrige pas
ce banc historique et ne revendique pas une suite complète de génération.
`./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true
-PsanctuarySolo232ClientTests=true -PsanctuaryClientGraphicsBackend=vulkan`
réussit en 1 min 3 s, Vulkan confirmé avec MoltenVK 1.4.2. Un propriétaire
Survie sans Allow Commands utilise réellement la commande de fuseau. Deux
groupes successifs sont minés avec R + clic gauche maintenus, huit destructions
et huit usages natifs d'outil ; un outil cassé interrompt le geste après une
destruction sans redémarrer. L'essai Balance080 couvre aussi pose native aux
deux mains, portée initiale, contour et pose à 6,75 blocs, refus d'un paquet
forgé à 7,25 blocs, indépendance Minage/Construction, contenants, nénuphars,
construction groupée et bonus externes.
Le menu pause est contrôlé avant/après achat Atlas, en FR/EN, aux échelles
GUI 2/3/4 dans une fenêtre 1280×960 : huit actions présentes et dans le corps,
colonnes sans chevauchement, carte uniquement après achat. Douze captures
sont conservées dans `build/solo232-screenshots/`, avec inspection visuelle
du mode verrouillé FR/2 et EN/4, et du mode débloqué FR/2. Les libellés longs
gardent les infobulles natives aux petites largeurs.
Log : `build/solo232-client-vulkan-final.log`, marqueurs `SOLO232_PASS` et
`BALANCE080_PASS`. Aucun essai OpenGL ou Windows n'est revendiqué.
MRpack local : `build/Sanctuary-beta.232.mrpack`, intégrité ZIP, versions,
dépendances exactes, JAR construit identique, absence de monde et d'entrée
Sanctuary Test vérifiées. Reçu : `build/solo232-mrpack-receipt.json`.
SHA-256 pack : `03e588c3866ad513d057162e9fea4ba9ad07e33a522841e2e7bbd66356b153f8`.
SHA-256 JAR : `a208ccce6318ceccf04d35d983e4a9ea1d46e872fda202d47a37000faa740d9f`.
Aucun monde personnel, installation de jeu ou canal packwiz n'est modifié.
+120
View File
@@ -0,0 +1,120 @@
# WG-209 — premier Sud, canyons multicolores
Branche `codex/south-badlands-beta209`, depuis beta.208 (`d021341`).
Le créateur valide le Nord 208 et demande ce premier prototype jouable du Sud.
## Contrat
Expansion Sud de diamètre 1024 : réseau de vallées creusées par Voronoi inversé,
mesas à plusieurs altitudes, falaises et petites ouvertures par bruit 3D.
La forme et la matière sont indépendantes. Les seize terracottas forment des
strates continues, plissées et marbrées ; leur disposition varie avec la graine.
Poudre de béton assortie sur les surfaces portantes, avec du sable rouge.
Pas de partage fixe en trois secteurs ni de roue chromatique autour de l'île.
Pas de nouvelle structure à cette étape : le test porte sur le relief et la matière.
Nouveaux profils 209 uniquement ; terrain de Sanctuary et Nord 208 conservés.
Tous les profils historiques restent disponibles, sans migration. Contrat de
test : nouveaux mondes de développement, graines 42 et 0, activation réelle de
l'ancre Sud et interruption/reprise de sa préparation. Nouvelle visite solo
Vulkan à 32 chunks, sans retoucher une sauvegarde existante. Export MRpack local ;
aucune publication de canal ni mise à jour Prism.
## Réalisation du prototype
- Sites Voronoi décalés par la graine, domaine déformé à grande échelle.
La distance aux frontières creuse un réseau ramifié ; sa largeur et sa
profondeur varient. Mesas à différentes altitudes, petits replats sur certains
flancs, rares creux sur les tables et alcôves en bruit 3D. Pas de simulation
globale d'érosion ou d'hydrologie. Les colonnes sont mises en cache par worker.
- Champ de matière indépendant : couches de sept blocs, plissées par deux
échelles horizontales et un bruit 3D. Les seize teintes sont groupées en
familles dont l'ordre et le sens varient avec la graine, sans secteurs radiaux.
- Une couche de poudre de béton assortie sur les surfaces peu inclinées et
soutenues ; plages de sable rouge. La terracotta constitue les parois et le
support. Végétation sèche native parcimonieuse, aucun lac ni structure ajouté.
L'économie des minerais et les temples du Sud restent pour la suite.
- Ancre Sud et relais suivants : climat aride, relief canyon et diamètre 1024 ;
petit éventail directionnel conservé. Préparation de 49 chunks d'arrivée et
neuf près du relais ; exploration progressive du reste. Signal SGA FR/EN.
- Presets 209 Small/Medium/Large et défaut Sanctuary. Densités de l'île principale
identiques aux fichiers 208 ; Nord délégué aux mêmes classes 208.
## Vérifications
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south209 -PsanctuaryAtlasOnly=true` :
succès en 5 min 43 s, contrôles purs et huit GameTests ciblés passés.
Journal : `build/south209-check-build.log`. Le Sud est contrôlé sur trois graines
pour ses vallées réparties, mesas, hauteurs, alcôves, appuis et déterminisme
entre workers. La palette conserve seize couleurs et une continuité spatiale ;
les anciens profils restent résolubles et les régressions du Nord passent.
La suite historique complète des GameTests n'est pas revendiquée.
Le premier essai natif a révélé un cycle d'ordre de décoration entre
`wooded_badlands` et le nouveau biome. La liste locale plaçait les buissons morts
avant l'herbe sèche ; elle reprend désormais l'ordre natif. Un GameTest charge
la liste complète des biomes de chaque taille et vérifie son tri topologique.
Reconstruction avec `:sanctuary:runGameTest build assemblePack assembleTestPack
:sanctuary-test:exportDuoLaunch -x :sanctuary:check`, même sélection ciblée :
succès en 47 s, neuf GameTests passés. Les contrôles purs précédents ne sont pas
répétés pour cette correction de ressource. Journal : `build/south209-order-fix.log`.
Les deux essais avortés sont conservés ; les essais finaux utilisent de nouveaux
répertoires `south209-b` (42) et `south209-b0` (0).
Les premiers essais corrigés `south209-b` et `south209-b0` passent : activation
réelle, reprise 0/58 → 58 FULL, seize couleurs, sables soutenus et biomes cohérents
dans les colonnes inspectées. Une revue finale limite explicitement ce champ au
diamètre 1024 : les commandes opérateur de plus petite taille gardent le canyon
historique. Le petit socle du relais descend jusqu'à six blocs si un vide local
le sépare du terrain. Un contrôle natif vérifie ses neuf appuis.
Reconstruction finale avec la même commande ciblée : neuf GameTests passés,
succès en 34 s (`build/south209-final-build.log`). Les essais finaux sur
`south209-final` (42) et `south209-final0` (0) passent également sur le JAR final.
Chaque serveur s'arrête proprement après vérification. Paiement réel, refus de
l'offrande incorrecte et du doublon, interruption à 0/58, reprise à 58 chunks FULL,
relais orienté Sud et message SGA vérifiés.
| Relevé | Graine 42 | Graine 0 |
| --- | --- | --- |
| Hauteurs sur la grille intérieure | 147–289 | 144–297 |
| Échantillons de vallée / mesa | 618 / 677 | 568 / 703 |
| Blocs inspectés dans les colonnes natives | 17 991 | 11 525 |
| Couleurs de terracotta observées | 16 | 16 |
| Sables inspectés / sans support | 89 / 0 | 120 / 0 |
| Colonnes avec biome attendu | 150 / 150 | 150 / 150 |
Ces relevés sont des échantillons, pas un inventaire de l'île entière. Les essais
simultanés ne constituent pas un benchmark de performances. Aucun essai Windows
ni validation esthétique n'est déduit de ces contrôles.
## Distribution et visite
`build/Sanctuary-beta.209.mrpack`, copié dans `~/Downloads/`. Archive ZIP intacte,
JAR identique au build, presets 208 et 209 des trois tailles présents, aucun
module Test ni monde embarqué. Minecraft 26.3 / Fabric Loader 0.19.5.
Reçu : `build/south209-mrpack-receipt.json`. SHA-256 :
`e077ce64f59330c4916408d0ff79f8d0e445bcfb3a972953680ccc93c28392b7`.
Aucun canal public, serveur personnel ou instance Prism mis à jour.
Visite neuve `Sanctuary-South-209-42`, copie de l'essai final arrêté, dans
`build/worldgen-lab/south209-visit/small/42/client/saves/`. Vue 32 chunks,
simulation 5, créatif en vol et commandes. Position initiale :
**(-167.5, 323.13, 585.5)**, regard vers **(-112, 304, 656)**.
Arrivée du Sud : **(128, 258, 664)** ; relais : **(104, 241, 1248)**.
L'ancienne visite 208 a été arrêtée par son hook de sauvegarde natif ; sa
sauvegarde et les anciennes visites sont conservées.
## Limites du prototype
Relief et palette à apprécier en jeu. Pas encore de temple, de défi ou de
nouvelle distribution de minerais propre au Sud. Les couches et affleurements
colorés sont présents ; des gisements spéciaux distincts restent une piste.
Le rendu et le coût d'exploration à 32 chunks ne sont pas validés par les mesures
de préparation du relais.
Le client confirme Vulkan sur Apple M1 et `SOUTH209_VISIT_OPEN` le 5 octobre
à 04:26:12 en **(-168, 323, 585)**. Vue 32 / simulation 5 confirmées. Le journal
indique ensuite le passage du joueur en spectateur ; cela confirme l'accès à la
visite, sans constituer une validation esthétique du prototype.
+93
View File
@@ -0,0 +1,93 @@
# WG-213 — Pyramide camouflée et chambres enterrées
Branche `codex/south-buried-beta213`, depuis beta.212 (`3941bd4`).
## Contrat
R017 valide le relief 212, les récifs relevés et les couleurs radiales. Retirer
seulement les sables normal / rouge de surface et les acacias custom du Sud.
Remplacer le complexe extérieur par une pyramide de terracotta locale, une
descente, environ dix petites salles dans le sol, couloirs étroits et pièges.
La taille du complexe vient du nombre de pièces. Le site peut être ailleurs
que le centre. Aucun autre changement de paysage ou chantier de jeu.
Nouveaux profils 213 uniquement : aucun monde existant modifié ou régénéré.
Générateur `SouthRelief212` repris sans changement, même graine et bruit ;
palette 212 conservée. Le Nord et l'île de départ gardent leur génération.
Contrat de vérification : création neuve sur 42/0, ancre réelle, reprise,
inspection native et nouvelle visite Vulkan 32 chunks ; MRpack local.
Aucun canal public, serveur personnel ou instance Prism modifiés.
## Réalisation
- Le sol conserve la terracotta et ses petites zones de terre stérile ; aucun
sable ou acacia ajouté par le nouveau profil Sud. Herbes / buissons secs conservés.
- Pyramide extérieure de 23 blocs de côté et 10 blocs au-dessus du sol, palette
résolue sur les vraies strates de ses coordonnées. Deux niveaux de cinq salles,
sols à 16 et 30 blocs sous l'entrée ; intérieurs 5 × 5, hauteur libre 3.
- Escaliers et couloirs de deux blocs de large. Dix coffres avec le butin déjà
vérifié en 212. Huit poches de trois TNT, déclenchement par plaque ; pas de
nappe explosive continue. Les pièces sont creusées dans la roche et bordées
d'une enveloppe mince, les anciennes halles / pylônes / arches sont absents.
- Recherche déterministe dans l'île : couvre les plafonds des salles et préfère
une masse rocheuse assez pleine. Tolère des fissures naturelles localisées.
Placement limité au chunk courant, préparation inclut le nouveau complexe.
## Vérifications de code
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south212,south213 -PsanctuaryAtlasOnly=true`
réussi en 2 min 37 s, contrôles purs et **12 GameTests** passés
(`build/south213-final-build.log`). La première passe avait trouvé un accès
bloqué sous la première descente : un petit contournement dessert maintenant
les chambres du premier niveau (`build/south213-check-build.log`).
Comparaison exacte des densités et palettes 212/213 sur deux graines : relief
et couleurs identiques. Les trois fichiers de bruit de l'île principale sont
identiques octet pour octet. Contrôles des profils historiques, du Nord et de
l'ancien Sud. Parcours des deux escaliers, accès aux dix chambres et coffres,
poches de TNT séparées ; test natif d'amorçage de la plaque conservé dans 212.
La suite complète des GameTests historiques n'est pas revendiquée.
## Essais natifs et distribution
Nouveaux mondes `south213-final` (42) et `south213-final0` (0), départ Small et
expansion Sud 1024. Paiement réel de l'ancre, mauvais paiement / doublon refusés,
interruption puis reprise, relais et signal SGA vérifiés. La préparation inclut
la pyramide et son sous-sol. Les deux serveurs sont arrêtés proprement avant
la copie de la visite ; aucune modification des visites précédentes.
| Relevé borné | Graine 42 | Graine 0 |
| --- | --- | --- |
| Hauteur maximale sondée (identique à 212) | 301 | 304 |
| Colonnes rehaussées (identiques à 212) | 281 | 211 |
| Sable normal / rouge | 0 | 0 |
| Troncs / feuilles d'acacia | 0 / 0 | 0 / 0 |
| Faces froides colorées exposées | 1485 | 1418 |
| Coffres / piles enchantées | 10 / 10 | 10 / 10 |
| TNT dans huit poches distinctes | 24 | 24 |
| Roche préexistante sondée autour des pièces | 100 % | 95,56 % |
| Base de la pyramide | 32, 249, 848 | −112, 249, 944 |
Le rendu de chaque bloc de terracotta de la pyramide correspond à la palette
locale. Les plafonds des pièces sont sous le toit du terrain et leur espace
libre est contrôlé dans les chunks réels. Ces mesures sont des échantillons,
pas un inventaire de toute l'île ou un benchmark. Aucun test Windows ni
validation visuelle du joueur n'est revendiqué. La petite structure a un plan
fixe pour cette itération ; son emplacement, orientation et teinte varient.
MRpack normal exporté, ZIP intact, JAR exact et presets des trois tailles
212/213 vérifiés, aucun monde ou module Test inclus. Copie dans
`~/Downloads/Sanctuary-beta.213.mrpack`. Minecraft 26.3, Fabric Loader 0.19.5.
SHA-256 : `6d11e398a09f6f65c963eb022bc0482906a8126e0c4f67ffbee867cadbe1340c`.
Reçu : `build/south213-mrpack-receipt.json`. Aucun tag ou canal public publié.
Nouvelle visite `Sanctuary-South-213-42`, sous
`build/worldgen-lab/south213-visit/small/42/client/saves/`, créatif en vol,
commandes, Vulkan, 32 chunks / simulation 5. Départ **(31.5, 263, 810.5)**,
face à l'entrée **(32, 250, 837)**. Relais **(128, 251, 1224)**.
Client ouvert à **06:32:38 CEST le 5 octobre 2026** : `SOUTH213_VISIT_OPEN`,
monde et position attendus. Backend Vulkan et options 32/5 confirmés.
Le rendu reste à apprécier par le joueur.
+137
View File
@@ -0,0 +1,137 @@
# WG-216 — Forêts et pièges du Sud
Branche `codex/south-forest-beta216`, depuis beta.215 (`03aab49`).
## Contrat
Retirer les torches de la pyramide, disperser davantage de plaques de pression
reliées à des pièges dans les salles et passages, conserver l’architecture et
le butin validés. Planter de grandes forêts denses sur les nappes de terre du
Sud, sans réintroduire les acacias rejetés. Choix de cette passe : chênes
ramifiés natifs avec des hauteurs variées et une canopée continue.
Le joueur considère le Sud terminé pour le moment après ces ajustements.
Nouveaux profils 216 uniquement, aucune ancienne sauvegarde ou chunk retouché.
Relief, couleurs, Nord et monuments 215 conservés. Mondes jetables neufs sur
42 et 0 : activation Sud, interruption et reprise autorisées pour les essais.
Nouvelle visite Vulkan 32 chunks et MRpack local, aucun canal public ni Prism.
## État
Implémenté ; build, huit GameTests ciblés et essais natifs sur 42/0 réussis.
MRpack exporté et vérifié ; nouvelle visite ouverte. Rendu à apprécier en jeu.
## Complément R022
Uniquement des arbres classiques, aucun acacia. Ajouter des chemins de terre
sur la surface de l’expansion, répartis entre les lieux et secteurs boisés.
Implantation sur le relief existant ; détours autour des failles, pas de pont
ou terrassement massif ajouté par cette passe.
Palette R023 : 14 teintes dans 8 couronnes, conservées sur choix explicite du joueur.
## Réalisation
La pyramide conserve ses dix salles, ses coffres et son enveloppe de 31 × 31.
Le gabarit 216 retire les torches et répartit des plaques dans les chambres et
les couloirs ; chacune repose sur un bloc plein, avec une charge TNT cachée
en dessous. Les anciens gabarits conservent leur éclairage et leurs pièges.
Les chênes utilisent le générateur ramifié natif de Minecraft 26.3, avec un
tronc de hauteur variable (paramètres 8 + aléas 7/3) et 18 essais de plantation
par chunk. Plantation uniquement sur les nappes existantes de terre, terre
stérile ou herbe ; réserve autour de la pyramide, du relais, de l’arrivée et
des chemins. Aucun acacia ni changement des couleurs de terracotta.
Les chemins sont calculés une fois par expansion, sur une grille de 16 blocs
avec vérification du sol à chaque pas. Dix destinations couvrent le relais,
la pyramide et les huit secteurs de l’île. La recherche privilégie les détours
praticables, puis peint des sentiers de trois blocs de large, resserrés sur
les bords. Les plateaux séparés par le vide ont des réseaux locaux distincts :
aucun pont ni remblai ne les raccorde artificiellement. Les destinations sont
approchées selon la praticabilité du terrain, sans garantie de liaison complète
entre tous les monuments. Plan indexé par chunk ; aucune prégénération de
l’île entière, aucun recalcul à chaque tick.
Les profils 216 Small/Medium/Large et le biome `sanctuary:south_badlands216`
isolent cette évolution. Les reliefs, matériaux et anciens profils restent
lisibles. Le nouveau biome n’ajoute que le placement des chênes.
## Vérifications
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,relays215,south216 -PsanctuaryAtlasOnly=true`
réussit : contrôles purs et huit GameTests ciblés. Plaque avec déclenchement
réel d’une TNT enterrée, accès aux dix chambres, conservation des anciens
profils et des relais. Planification directe : dix branches et 4 962 cellules
sur la graine 0 ; dix branches et 5 230 cellules sur 42. Parcours vérifiés
bloc par bloc, reconstruction identique du plan. Ces graines directes diffèrent
des graines dérivées utilisées lors d’une activation depuis Sanctuary.
Comparaison des ressources : bruit de terrain identique à 215 pour les trois
tailles ; préréglages modifiés uniquement pour leur révision et le biome 216.
Code de sélection des couleurs strictement identique : 14 teintes, 8 couronnes.
Les premiers essais ont décelé une recherche de sentiers bloquée dans un petit
secteur isolé. La planification distingue désormais les plateaux reliés à pied
et produit des réseaux locaux, sans franchissement artificiel du vide.
## Mondes générés et reprise
Essais finaux `south216-final` (42) et `south216-final0` (0), après correction
du relevé des arbres : les branches horizontales touchant une paroi étaient
comptées à tort comme des racines. La règle de plantation n’a pas changé ;
le relevé contrôle désormais les troncs verticaux. Le premier contrôle natif
avait aussi exigé une pyramide sur 0 alors que la recette conservée n’y trouve
pas de site enterré. Ce cas est relevé explicitement, pas converti en réussite
de placement. Le contrôle exige toujours la pyramide sur 42.
Activation par l’ancre Sud, paiement, rejet d’un doublon, interruption et
reprise réussis dans les deux mondes. Île principale Small 512, expansion de
1024 centrée en (128, 944). Graines dérivées : −6763683964522674921 (42) et
3285501279717306940 (0).
| Relevé natif | 42 | 0 |
| --- | ---: | ---: |
| Branches de sentiers | 10 | 9 |
| Cellules de chemin prévues | 3 509 | 2 106 |
| Blocs de chemin vérifiés dans les chunks | 470 | 478 |
| Chunks de chemin contrôlés | 10 | 9 |
| Troncs dans la zone forestière de 49 × 49 | 69 | 97 |
| Chênes avec tronc d’au moins 8 blocs | 61 | 91 |
| Colonnes couvertes par les feuilles | 1 657 | 2 177 |
| Blocs de feuilles | 13 210 | 17 054 |
| Acacias dans le relevé | 0 | 0 |
Chemins soutenus et deux blocs libres au-dessus ; troncs verticaux sur terre.
Les monuments des relais sont comparés au plan bloc par bloc (2 326 / 2 217
blocs), avec accès et paiement sur leur position surélevée.
Pyramide de 42 en (32, 249, 848) : 10 coffres, 10 piles enchantées,
40 plaques de pression, 56 TNT et **aucune torche**. Les galeries restent
accessibles avant déclenchement. Sur 0, aucune pyramide : limite du placement
215 conservé, qui refuse un massif insuffisamment plein. Les routes n’assurent
pas une liaison continue à travers toutes les failles. Ces essais ne sont
ni un benchmark, ni une validation graphique du rendu, ni un essai Windows.
## Distribution locale
`build/Sanctuary-beta.216.mrpack`, également copié dans Downloads, contient le
mod normal avec les trois tailles ; aucun module Test ni monde. Intégrité ZIP,
version, profils historiques et identité exacte du JAR construit vérifiés.
SHA-256 MRpack : `e5c9c6bd9a1a4602f290732a9adf49652c217ab4858db256e3cfe6d8ee1f2bf3`.
SHA-256 JAR : `0807809aa1e8c889cb84e56de99e24f8b3702dd72bba5e56f809bbb4854f23d2`.
Après les corrections de diagnostic uniquement, le module Test a été recompilé
et réassemblé ; le JAR principal reste exactement celui du `check build` réussi.
Reçus ignorés : `build/south216-static-receipt.json`,
`build/south216-mrpack-receipt.json` et rapports `warm.json` des deux essais.
Nouvelle sauvegarde de visite : `south216-visit-final`,
`Sanctuary-South-216-42`, copie neuve du monde vérifié, créatif avec commandes,
vue 32 chunks et simulation 5. Départ face à la forêt en (284, 204, 1170),
forêt en (256, 172, 1200), relais en (128, 258, 1224).
Aucun ancien monde modifié ; aucun canal public, tag ou Prism mis à jour.
Ouverture confirmée par `SOUTH216_VISIT_OPEN` le 5 octobre 2026 à 08:36:18 CEST,
position (284, 204, 1170), backend Vulkan confirmé dans le journal client.
+122
View File
@@ -0,0 +1,122 @@
# WG-210 — familles de teintes et sols des canyons
Branche `codex/south-palette-beta210`, depuis beta.209 (`efb1097`).
## Contrat
Le créateur accepte le relief du Sud 209 et demande une famille de teintes
terreuses par massif, des strates irrégulières moins contrastées, un fond de
canyon continu et de la végétation sèche dans les vallées et sur les plateaux.
Conserver strictement la densité, les dimensions, les alcôves et les relais.
Ni dégradé systématique sombre/clair selon l'altitude ni cycle des seize couleurs.
Nouveaux profils 210 uniquement ; les mondes et profils historiques restent
inchangés. Tests autorisés sur de nouveaux mondes de développement, graines 42
et 0 : activation de l'ancre Sud, interruption/reprise, contrôle du terrain
natif et nouvelle visite Vulkan à 32 chunks. Export MRpack local. Pas de
migration de sauvegarde, publication de canal ou déploiement Prism.
## État
Implémentation compilée ; contrôles ciblés et essais natifs 42/0 réussis. Le jugement esthétique
reste à apporter en visite ; les contrôles techniques ne valident pas le rendu.
## Réalisation
Le champ `SouthRelief209` conserve ses calculs de densité. Il expose seulement
l'identifiant du massif Voronoi déjà choisi et le fond théorique de vallée.
`SouthTerrain210` réutilise ce champ et les sites d'arrivée/relais 209.
`SouthPalette210` prépare quatre familles apparentées : rouille, ocre, terre,
crème. Pour chaque massif, une roche dominante couvre l'essentiel du volume ;
des lits secondaires de 2–6 blocs et des filets de 1–2 blocs interrompent des
espacements de 8–26 blocs. Les piles sont indépendantes, déterministes par graine
et légèrement plissées. Le pied des massifs reste en terracotta commune.
Le cycle des seize teintes et les poudres colorées restent propres au profil 209.
Les fonds plats reçoivent un sol commun de terre stérile, terre et sable rouge,
piloté par un bruit continu indépendant des cellules. Les plateaux reçoivent des
plages de sol et conservent des affleurements. Le sable repose sur du grès rouge.
Cette passe remplace les blocs solides existants ; elle ne creuse ni ne remplit
les vallées. La continuité porte sur le sol, aucune rivière n'est ajoutée.
L'herbe sèche courte/haute, les buissons morts et quelques cactus sont placés
sur les surfaces portantes des vallées et des plateaux. Les règles natives de
support sont vérifiées. Les candidats restent à l'intérieur de leur chunk et
ne lancent aucune recherche de terrain supplémentaire. Le biome 210 a une liste
de features vide : cette décoration locale évite d'ajouter deux fois les plantes.
Les trois tailles publiques basculent vers des profils 210 avec les mêmes
réglages de l'île principale ; le Nord conserve le champ accepté en 208.
Les profils 196–209 restent chargeables et ne changent pas de palette.
## Vérifications de compilation et de comportement
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south209,south210 -PsanctuaryAtlasOnly=true`
réussit en 2 min 49 s : contrôles purs et 11 GameTests ciblés passés.
Journal `build/south210-check-build.log`. La suite historique complète des
GameTests n'est pas revendiquée.
Les tests couvrent les densités et relais 209/210 identiques sur trois graines,
la dominante par massif, les quatre familles, l'irrégularité des couches, leur
continuité spatiale, le sol de vallée indépendant de l'identité du massif et
les sols des plateaux. Ils conservent les contrôles du Nord 208, de la palette
historique 209 et des trois tailles publiques avec leurs anciens profils.
Les trois JSON de densité de l'île principale sont identiques octet pour octet
aux profils 209 ; aucune migration n'est effectuée.
Contrôles natifs réalisés sur de nouveaux mondes 42/0 ; résultats ci-dessous.
Le premier essai 42 passe avec 1 493/1 493 colonnes de vallée éligibles couvertes
par le sol et des plantes sèches en vallée comme sur mesa. L'échantillon initial
0 n'observait que trois teintes dans les points d'arrivée, du relais et du canyon ;
il ne visitait pas les quatre familles. Le contrôle natif inclut désormais une
mesa représentative de chaque famille avant de compter les matériaux. Aucun
changement du générateur n'est effectué pour ce correctif d'échantillonnage.
Reconstruction ciblée : 11 GameTests passés en 17 s, journal
`build/south210-final-build.log`. Nouveaux essais `south210-verified` (42) et
`south210-verified0` (0), les premières traces étant conservées.
## Résultats natifs finaux
Les deux essais passent, avec ancre réelle, paiement, refus du mauvais objet et
du doublon, interruption à 0/58, reprise à 58 chunks FULL, neuf appuis de relais
soutenus et signal SGA. Les serveurs sont arrêtés proprement après contrôle.
Les hauteurs et sites de relais correspondent aux relevés 209 des mêmes graines.
| Relevé | Graine 42 | Graine 0 |
| --- | --- | --- |
| Hauteurs intérieures | 147–289 | 144–297 |
| Colonnes avec biome attendu | 250 | 250 |
| Blocs natifs inspectés | 29533 | 24317 |
| Teintes observées parmi les quatre familles | 7 | 7 |
| Sables inspectés / sans support | 50 / 0 | 4 / 0 |
| Sol continu dans la vallée contrôlée | 1493 / 1493 | 1325 / 1325 |
| Plantes sèches, secteur vallée | 39 | 29 |
| Plantes sèches, secteur mesa | 45 | 18 |
Les relevés portent sur des échantillons, pas sur l'île entière. Les plantes
observées sont des herbes sèches et buissons morts ; les rares cactus prévus
n'apparaissent pas dans ces deux petits secteurs. Aucun benchmark, essai Windows
ou jugement esthétique n'est déduit des tests serveur.
## Distribution et visite
`build/Sanctuary-beta.210.mrpack`, copié dans `~/Downloads/`. Intégrité ZIP,
version, identité du JAR construit, trois tailles 209/210 et absence de mondes
ou de module Test vérifiées. Minecraft 26.3 / Fabric Loader 0.19.5.
Reçu `build/south210-mrpack-receipt.json`. SHA-256 :
`eb91fe9f037b52f5ac4ef273d45ee2ad2ce4e85b5b24870ed627ba1672d60ce5`.
Visite neuve `Sanctuary-South-210-42`, copie de l'essai 42 arrêté, dans
`build/worldgen-lab/south210-visit/small/42/client/saves/`. Vulkan, 32 chunks,
simulation 5, créatif en vol et commandes. Même départ que la visite 209 :
**(-167.5, 323.13, 585.5)**, regard vers **(-112, 304, 656)**.
Arrivée **(128, 258, 664)** ; relais **(104, 241, 1248)**.
Client ouvert à 05:02:17 CEST le 5 octobre 2026 : marqueur
`SOUTH210_VISIT_OPEN`, monde et position attendus, backend Vulkan confirmé.
Les anciennes visites sont conservées ; aucun canal public ni instance Prism
n'est modifié. Les temples et ressources propres au Sud restent hors de ce lot.
+109
View File
@@ -0,0 +1,109 @@
# WG-212 — Couronnes des Badlands et complexe du désert
Branche `codex/south-rings-beta212`, depuis beta.211 (`7375046`).
## Contrat et retours
R013 valide la base 211, critique le grand plateau et le cœur coloré invisible.
Rendre les couleurs concentriques visibles, ajouter du sable normal, de vrais
arbres secs et petits arbres feuillus, relever localement les plateaux.
R014–R016 précisent un grand complexe allongé, du butin et beaucoup de TNT.
La recherche d'une emprise parfaitement soutenue est abandonnée explicitement :
accepter encastrements et surplombs dans le terrain 3D, avec une architecture qui
les accompagne. Le complexe peut se décaler du centre.
Diamètre Sud 1024. Nouveaux profils 212 uniquement ; aucune migration ni
régénération des mondes antérieurs. Nord 208 et île principale conservés.
Contrat de test : nouvelles graines 42/0, activation réelle et reprise, contrôles
natifs, puis nouvelle visite Vulkan 32 chunks et MRpack local. Pas de publication
publique, de déploiement Prism ou de serveur personnel.
## Mise en œuvre
- Densité 211 conservée en profondeur, et couronnes de mesa localisées au-dessus
de roches hautes portantes. Données de cellules Voronoi 209 réutilisées pour le relief,
sans ses gradins ni son ancienne dalle. Les fissures 3D continuent dans les ajouts.
- Huit familles radiales légèrement déformées, visibles sur les toits et parois.
Les bandes natives de `MaterialSystem` choisissent les nuances de chaque famille.
- Désert central de sable normal / grès, nappes secondaires et végétation sèche.
Acacias dénudés ramifiés et petits arbres feuillus ; placement entier et borné
dans le chunk. Le temple réserve sa place avant décoration.
- Complexe de grès allongé, chambres latérales, galerie, sanctuaire haut et cache
dissimulée. Piliers courts et arches sous les parties suspendues. Six circuits
de pièges, 108 TNT et huit coffres : fer enchanté, provisions, minerais et gemmes.
Plan déterministe en mémoire, placement limité au chunk courant. Tous ses
chunks sont inclus dans la préparation de l'expansion avant le signal SGA.
## Vérifications de code
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south211,south212 -PsanctuaryAtlasOnly=true`
réussi : contrôles purs et 11 GameTests. Après optimisation du planificateur,
restriction des arches à l'emprise construite et ajout d'un test d'amorçage réel,
reconstruction avec `:sanctuary:runGameTest build assemblePack assembleTestPack
:sanctuary-test:exportDuoLaunch -x :sanctuary:check`, même sélection : **12 tests
passés**, build réussi. Traces `build/south212-check-build.log`,
`build/south212-final-build.log`, `build/south212-release-build.log`.
Couverture : profils courants et historiques sans module Test, Nord accepté,
ancien Sud, cavités 211 conservées en profondeur, ajouts localisés, vides non
rebouchés par le relief, déterminisme entre workers, huit familles radiales,
complexe planifié sur deux graines, communication des pièces, contenu des pièges
et TNT réellement amorcée par une plaque via son sol. Les trois réglages de
bruit de l'île principale sont identiques octet pour octet à ceux de 211.
Les profils historiques et leurs Java restent inchangés. Le test complet de
code n'inclut pas tous les GameTests historiques ; sélection ciblée ci-dessus.
Le premier essai natif a révélé une amplitude négligeable des ajouts : le seuil
utilisé convenait au champ synthétique du test, mais pas aux densités du bruit
réel. Seuil corrigé, assertion ajoutée sur le générateur natif et nouvelle
reconstruction ciblée réussie, 12 tests (`build/south212-crowns-build.log`).
Les mondes du premier essai sont conservés séparément ; les mesures finales
proviennent de mondes neufs avec la bonne empreinte des sources.
## Essais natifs finaux et distribution
Mondes neufs `south212-final2` (42) et `south212-final02` (0), île de départ Small
et Sud 1024. Ancre réelle, refus du mauvais paiement et du doublon, interruption
0/86 puis reprise 86 chunks FULL, relais soutenu et signal SGA vérifiés. Les deux
serveurs sont arrêtés proprement avant de copier la visite.
| Relevé borné | Graine 42 | Graine 0 |
| --- | --- | --- |
| Hauteur maximale sondée | 301 | 304 |
| Ajout maximal théorique | 53,44 | 53,50 |
| Colonnes sondées relevées de plus de 8 blocs | 281 | 211 |
| Faces colorées froides adjacentes à l'air | 1423 | 1364 |
| Sable clair / sans support | 39 / 0 | 36 / 0 |
| Troncs / feuilles dans les colonnes sondées | 11 / 28 | 3 / 8 |
| Coffres / piles enchantées | 8 / 8 | 8 / 8 |
| Blocs TNT dans le complexe | 108 | 108 |
| Origine du complexe | 64, 250, 912 | 32, 250, 976 |
Les huit familles sont testées dans le code ; cinq teintes froides sont
observées exposées dans chacun des deux relevés natifs. Ces sondages ne sont
ni un inventaire de toute l'île, ni un benchmark. Les essais simultanés ne
permettent pas de conclure à un gain de performances. Aucun test Windows ni
validation esthétique par le joueur n'est revendiqué.
Le complexe est un premier plan allongé fixe, dont le site et l'orientation
s'adaptent à la graine. Les surplombs sont voulus ; les piliers s'arrêtent au bout
de 24 blocs s'ils ne rencontrent pas de roche. Une recherche bornée à 96 positions
préfère une attache au terrain sans exiger une emprise parfaitement pleine.
L'accessibilité extérieure sur toutes les graines reste à apprécier en jeu.
MRpack normal exporté localement, ZIP intact, JAR exact vérifié, trois tailles
211/212 présentes, aucun monde ni module Test embarqué. Minecraft 26.3,
Fabric Loader 0.19.5. Copie `~/Downloads/Sanctuary-beta.212.mrpack`.
SHA-256 : `5ba08e99fd9c656df2199f8f0f479ce89cfd442d2e8f5ef00376294b8c5f02be`.
Reçu `build/south212-mrpack-receipt.json`. Aucun canal public ou tag publié.
Visite préparée `Sanctuary-South-212-42`, depuis l'essai final arrêté, sous
`build/worldgen-lab/south212-visit2/small/42/client/saves/`. Départ en vol
**(8.5, 326, 841.5)** face au temple **(64, 250, 912)** ; créatif, commandes,
32 chunks, simulation 5. Arrivée **(120, 249, 680)** ; relais **(128, 251, 1224)**.
Client ouvert à **06:10:21 CEST le 5 octobre 2026** : `SOUTH212_VISIT_OPEN`,
position et monde attendus. Backend Vulkan et distance 32 confirmés dans les
traces / options. Le rendu reste à apprécier par le joueur.
+113
View File
@@ -0,0 +1,113 @@
# WG-211 — Sud fracturé, badlands extérieurs et intérieur coloré
Branche `codex/south-shattered-beta211`, depuis beta.210 (`2ee53e1`).
## Contrat
R012 rejette le rendu et la forme 210 : trop uniforme, gradins visibles et
cavités tronquées. Repartir du canyon historique et du bruit 3D, sans Voronoi,
avec des badlands chauds dehors et des couleurs dedans. Diamètre confirmé à
1024 blocs. Hauteur actuelle comme référence ; dessous d'épaisseur variable.
Huit teintes internes pour ce prototype, nombre encore ouvert au jugement visuel.
Nouveaux profils 211 uniquement. Les sauvegardes et profils antérieurs restent
inchangés. Contrat de test : nouvelles graines 42/0, activation réelle du Sud,
interruption/reprise, inspection native et nouvelle visite Vulkan à 32 chunks.
Export MRpack local ; aucun canal public, serveur personnel ou Prism modifié.
## Références lues
Code Minecraft 26.3 local : `MaterialSystem.generateBands`, `getBand`,
`erodedBadlandsExtension` dans le JAR officiel utilisé par Loom. Les bandes
natives seront appelées directement. Le relief flottant réutilise le bruit 3D
natif déjà employé par les anciennes expansions, à son échelle en blocs ;
il ne remplace pas le monde entier par le générateur Overworld.
La [présentation officielle des Badlands](https://www.minecraft.net/en-us/article/around-block--badlands)
sert de référence d'ambiance ; la compatibilité est vérifiée sur le code 26.3.
Implémentation compilée et contrôles natifs réussis ; rendu à juger en visite.
## Réalisation
- `SouthNoise211` compile le champ flottant natif via `NorthNoise205`, sans
les montagnes Voronoi, gradins 209, remappage des plateaux ni canyon axial
d'`ExpansionRelief`. Des fissures en bruit 3D déformé traversent plusieurs
secteurs ; leurs terminaisons varient aussi en hauteur. La transformation
retire de la matière, sans reboucher les vides du champ initial.
- Le dessous suit le toit natif avec une épaisseur théorique de 44–102 blocs,
modulée continûment puis érodée. Les cavités et surplombs du bruit restent.
Caches bornés par worker ; pas de simulation d'hydrologie ni de carte globale.
- L'extérieur appelle `MaterialSystem.getBand` du Minecraft installé via un
invoker : vraies bandes natives et leur décalage, déterministes par graine.
L'intérieur emploie huit terracottas (rouge, orange, jaune, vert clair, cyan,
bleu, violet, magenta), en couches inégales légèrement plissées. Leur volume
reste sous le toit, au-dessus du dessous et à l'intérieur de la roche native.
Les fissures en révèlent des faces ; les peaux extérieures restent chaudes.
- Sable rouge soutenu, plages de terre stérile, herbes sèches, buissons morts et
cactus sur les surfaces peu inclinées. Aucun ajout de structure à ce lot.
- Les trois tailles de Sanctuary utilisent de nouveaux presets 211. Les anciens
presets, palettes et sauvegardes sont conservés. L'île de départ conserve ses
trois densités identiques ; le Nord continue d'utiliser 208. Expansion Sud 1024.
## Contrôles de code
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south210,south211 -PsanctuaryAtlasOnly=true`
exécute les contrôles purs, puis 9 des 10 GameTests passent. Le test des fractures
échantillonnait uniquement au-dessus de Y230, excluant les sommets plus bas d'un
secteur. Le relevé a été corrigé pour examiner les 30 blocs sous chaque toit,
sans modifier le générateur. Traces `build/south211-check-build.log` et
`build/south211-shape-check.log` conservées.
Reconstruction ciblée avec `:sanctuary:runGameTest build assemblePack
assembleTestPack :sanctuary-test:exportDuoLaunch -x :sanctuary:check`, même sélection :
succès en 20 s, **10 GameTests passés** (`build/south211-final-build.log`).
Couverture : profils publics/historiques, Nord accepté, ancienne palette 210,
soustraction seule du nouveau relief, fissures réparties, ordre des workers,
compilation native, huit teintes internes et bandes natives effectivement appelées.
La suite historique complète des GameTests n'est pas revendiquée.
## Essais natifs et distribution
Nouveaux mondes `south211-final` (42) et `south211-final0` (0), profil Small pour
l'île de départ et expansion Sud 1024. Ancre réelle, refus du mauvais paiement
et du doublon, interruption 0/58, reprise 58 chunks FULL, appuis du relais et
signal SGA vérifiés. Les deux serveurs sont arrêtés proprement après leurs tests.
| Relevé | Graine 42 | Graine 0 |
| --- | --- | --- |
| Hauteurs de la grille intérieure | 82–254 | 80–254 |
| Colonnes rocheuses | 1563 | 1462 |
| Ouvertures sondées sous le toit | 583 | 728 |
| Colonnes avec biome attendu | 300 | 300 |
| Blocs natifs inspectés | 10350 | 9935 |
| Blocs de cœur aux teintes froides | 1550 | 2236 |
| Dont faces adjacentes à de l’air | 29 | 70 |
| Blocs contrôlés dans les peaux chaudes | 3688 | 3460 |
| Sables / sans support | 137 / 0 | 74 / 0 |
Les huit couleurs internes sont contrôlées dans les GameTests. Les cinq teintes
froides distinctes de la peau vanilla sont toutes observées dans les deux
échantillons natifs. Plantes sèches présentes et soutenues. Ces comptages ne
couvrent pas l'île entière et ne valident ni l'esthétique ni les performances.
Les essais simultanés ne sont pas un benchmark ; aucun test Windows n'est revendiqué.
`build/Sanctuary-beta.211.mrpack`, copié dans `~/Downloads/`. Archive ZIP intacte,
version et JAR exact vérifiés, trois tailles 210/211 présentes, aucun monde ni
module Test embarqué. Minecraft 26.3, Fabric Loader 0.19.5.
SHA-256 :
`1779f71893b3feb3d72f64e9a262471a58df676b715ec6831213833bd697f96c`.
Reçu `build/south211-mrpack-receipt.json`. Pas de publication de canal ou de tag,
pas de déploiement Prism. Les anciennes visites sont conservées.
Nouvelle visite `Sanctuary-South-211-42`, copie de l'essai arrêté, sous
`build/worldgen-lab/south211-visit/small/42/client/saves/`. Vulkan, 32 chunks,
simulation 5, créatif en vol, commandes. Départ **(136.5, 288, 889.5)**, regard
vers **(192, 264, 960)**. Arrivée **(128, 249, 664)** ; relais **(128, 251, 1224)**.
Une paroi colorée échantillonnée se trouve autour de **(120, 186, 656)**.
Client ouvert à 05:27:18 CEST le 5 octobre 2026 : `SOUTH211_VISIT_OPEN`,
monde et position attendus, backend Vulkan confirmé. Les temples et minerais propres
au Sud restent pour la suite.
+111
View File
@@ -0,0 +1,111 @@
# WG-214 — Village abandonné du canyon
Branche `codex/south-western-beta214`, depuis beta.213 (`da838b9`).
## Contrat
Ajouter à la surface du Sud un village Far West décoratif en chêne noir :
sept ou huit maisons, rue principale, trois façades d’un côté et quatre ou
cinq de l’autre, porches, ornementation et lanternes. Disposition, dimensions
et usure varient avec la graine. Pas de PNJ, quête ou nouveau butin.
Relief, palette, pyramide et relais 213 conservés.
Nouveaux profils 214 uniquement. Aucun ancien monde, chunk ou journal converti.
Les profils historiques gardent leur recette. Vérification sur des mondes
jetables neufs, activation réelle de l’ancre Sud puis reprise autorisées pour
ces essais ; aucune activation dans une partie existante. Visite neuve Vulkan
32 chunks, distribution locale ; aucun canal public ou Prism modifié.
## Réalisation
`SouthVillage214` ajoute un village par expansion Sud 214, séparé du temple,
de l’arrivée et du relais. Sept ou huit maisons : trois d’un côté, quatre ou
cinq en face, avec inversion possible des côtés. Rue de 83 blocs, largeur
neuf ; trois rotations supplémentaires possibles. Façades de 7 à 11 blocs,
profondeur de 9 à 11, porches, corniches, fausses façades à décrochements,
toits inclinés, vitres brisées ou condamnées, toiles et mobilier simple.
Chêne noir, lanternes suspendues espacées, sol en terre stérile / enracinée.
Aucun coffre, table de butin, piège, villageois ou objectif ajouté au village.
Recherche déterministe et bornée (grille de 32 blocs) sur les surfaces déjà
produites. Rue suivant
les hauteurs réelles, raccords limités à trois blocs de coupe/remblai dans
la rue, fondations d’au plus cinq blocs vérifiées colonne par colonne, au
plus un bloc de roche dépassant le plancher des maisons. Le plan ne charge
aucun chunk et se conserve en cache ; pose indexée par chunk, réservée avant
la végétation. La préparation de l’expansion comprend les chunks du village.
Un site non supporté est refusé : une graine défavorable peut ne pas recevoir
de village, plutôt que produire des fondations traversant le vide.
Les profils 214 réemploient le terrain, la palette, le biome et la pyramide
213. Pas de copie divergente du générateur. Les profils antérieurs conservent
leur génération ; Nord et île principale inchangés.
## Vérifications
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,north208,south213,south214 -PsanctuaryAtlasOnly=true`
réussi en 2 min 50 s (`build/south214-verified-build.log`). Contrôles purs et
**9 GameTests ciblés** réussis. La suite historique complète des GameTests
n’est pas revendiquée.
Le nouveau test vérifie sur deux graines directes et la graine dérivée de
l’expansion du monde 0 les maisons accessibles depuis la
rue, les supports du plan, les lampes, la limite de chunks et l’absence de
conteneurs / TNT. Les tests 213 conservent les contrôles de la pyramide et du
relief ; le profil public courant et toutes les anciennes clés 196–213 sont
résolus sans module Test. Les trois fichiers de bruit de l’île principale
214 sont identiques octet pour octet aux fichiers 213.
Pendant le développement : deux usages d’API ChunkPos ont été adaptés à 26.3 ;
un test de sélection attendait encore 213 et a été actualisé en conservant
l’assertion historique. Relecture des marches : leur hauteur rejoint désormais
la rue aménagée, pas le sol latéral avant aménagement. La première génération native a trouvé le village sur 42, mais pas sur 0.
La recherche affinée et la rue légèrement nivelée corrigent ce cas ; cette
graine dérivée, avec ses coordonnées réelles, rejoint le test de placement.
La dernière commande ci-dessus vérifie cette version finale.
## Essais natifs
Nouveaux mondes `south214-verified` (42) et `south214-verified0` (0), île Small,
expansion Sud 1024. Activation réelle de l’ancre, mauvais paiement / doublon
refusés, interruption puis reprise et relais final contrôlés. Les serveurs
sont arrêtés proprement après chaque phase. Aucune ancienne visite modifiée.
| Relevé | Graine 42 | Graine 0 |
| --- | --- | --- |
| Centre du village | −64, 251, 880 | 32, 251, 976 |
| Maisons | 8 (3 + 5) | 8 (3 + 5) |
| Chunks du village | 22 | 23 |
| Lanternes / toiles | 6 / 10 | 6 / 10 |
| Chunks préparés pour l’expansion | 89 | 87 |
| Coffres / TNT de la pyramide | 10 / 24 | 10 / 24 |
Tous les blocs du plan sont comparés aux blocs des chunks réels. Supports
sous les planchers, hauteur des portes, parcours rue → intérieur et tenue des
lanternes vérifiés. La pyramide conserve ses dix piles enchantées ; le contrôle
des matériaux ne trouve ni les anciens acacias ni les sables supprimés en 213.
Les caches de plan sont reconstruits à la réouverture aux mêmes emplacements.
Ces relevés ne constituent pas un benchmark, un test Windows ou une validation
esthétique. Sur les deux graines directes du test de placement, les plans ont
respectivement huit et sept bâtiments ; les deux visites natives en ont huit.
## Visite
Nouveau solo `Sanctuary-South-214-42`, dossier
`build/worldgen-lab/south214-visit/small/42/client/saves/`.
Créatif en vol, commandes, ciel clair, 32 chunks / simulation 5, Vulkan.
Départ **(−12.5, 265, 880.5)**, face à la rue centrée en **(−64, 251, 880)**.
Ouvert le 5 octobre 2026 à **07:21:04 CEST**, confirmé par
`SOUTH214_VISIT_OPEN` avec le monde et la position attendus. Backend Vulkan
(MoltenVK 1.4.2) et options 32/5 confirmés dans les logs / réglages. Le jugement
visuel appartient à la nouvelle visite ; aucune capture ou approbation du joueur
n’est annoncée.
## Distribution locale
MRpack exporté, intégrité ZIP, version et JAR exact contrôlés ; profils 213/214
Small/Medium/Large présents, aucun monde ou module Test inclus.
`~/Downloads/Sanctuary-beta.214.mrpack`.
SHA-256 : `4e28fc3c5f00464f2fb37f7b2bcbba9ef8edcd23fffdc8a321d26f2bd31ddb02`.
Reçu : `build/south214-mrpack-receipt.json`. Aucun canal public ou tag publié.
+80
View File
@@ -0,0 +1,80 @@
# STORY-234 — recherche et filtres
Branche `codex/story-beta234`, base beta.233, commit `9c096b2`, Minecraft 26.3.
## Contrat
Story apparaît sous Progression dans Aventure, avant et après Atlas. Il reprend
le cadre de Discovery : titre, séparateurs et Terminé / Done. La recherche et
le filtre Toutes / Découvertes / Inconnues remplacent les boutons de catégories.
La liste réserve 100 histoires numérotées et inconnues, toutes désactivées.
Toutes et Inconnues montrent les entrées correspondant à la recherche, dans
l'ordre numérique ; Découvertes indique qu'aucune histoire n'est découverte.
Une recherche sans résultat dispose d'un autre message. La recherche porte sur
le numéro et le libellé visible, ignore la casse et les espaces extérieurs.
Recherche et filtre se combinent et ramènent le défilement en haut. La saisie
garde son focus et son curseur ; redimensionner garde recherche, filtre et
défilement. Terminé et Échap reviennent directement au menu Pause d'origine.
Aventure comprend maintenant Discovery, Progression et Story. Les trois groupes
de Pause conservent leur ordre avec ou sans carte. Aux petites hauteurs, les
boutons et espaces se compactent pour éviter les chevauchements.
[Guide de rédaction](story/README.md) et [modèle Markdown](story/TEMPLATE.md) :
un fichier `001.md` à `100.md`, avec numéro, titre, texte et idée de découverte
facultative. Aucun récit n'est inventé, chargé ou révélé dans ce lot. Leur
intégration et leurs déblocages seront des tickets suivants. Pas de nouveau
paquet réseau, dépendance, sauvegarde ou changement de génération.
## Vérifications
```sh
./gradlew check build assemblePack -PsanctuaryFocusedTests=menus -PsanctuaryAtlasOnly=true
./gradlew :sanctuary:runClientGameTest -PsanctuaryClientTests=true -PsanctuaryStory234ClientTests=true -PsanctuaryClientGraphicsBackend=vulkan
```
Build final réussi en 2 min 34 s : quatre GameTests requis et contrôles purs du
dépôt, dont les contrôles communautaires fichier, photos, demandes et recherche.
Log : `build/story234-check-build-pack-final.log`. Le banc menus utilise la
sélection Atlas existante ; le conflit du générateur sur le chemin par défaut,
documenté en beta.232, n'est pas modifié par ce lot.
Parcours client final réussi en 30 s (`STORY234_PASS`), sur un monde plat neuf
de développement en Survie sans commandes. Vulkan confirmé par le journal :
MoltenVK 1.4.2 sur macOS, Apple M1. Log : `build/story234-client-vulkan-final.log`.
- FR/EN, GUI 2/3/4, fenêtre 1280 × 960, avec et sans Atlas : six actions
Sanctuary dans l'ordre visuel et clavier, trois groupes sans chevauchement,
groupe Discovery/Progression/Story centré verticalement.
- 100 numéros consécutifs sans doublon, entrées désactivées, recherche du numéro
100, espaces extérieurs et recherche en majuscules dans le libellé localisé.
Recherche et filtre combinés, deux états vides distincts.
- Saisie par événements natifs, focus et curseur conservés, molette et accès à
la dernière entrée ; défilement remis en haut après recherche ou filtre.
Redimensionnement réel à 1344 × 1008 : recherche, filtre et défilement conservés.
- Terminé et Échap reviennent à la même Pause. La page reste une pause solo ;
le record de progression serveur est identique avant et après les consultations.
21 captures dans `build/story234-screenshots/`. Captures inspectées : Story FR/2
et EN/4, Pause sans Atlas FR/4 et avec Atlas EN/3, états Découvertes et recherche
vides, recherche de l'histoire 100. L'indication de recherche reste visible
lorsque le champ vide a le focus. Aucun essai OpenGL ou Windows n'est revendiqué.
## Livraison locale
`mod_version`, `pack_version` et `packwiz/pack.toml` sont alignés sur beta.234.
Export [Sanctuary-beta.234.mrpack](../build/Sanctuary-beta.234.mrpack),
12 775 502 octets : intégrité ZIP, Minecraft 26.3, Fabric Loader 0.19.5,
un seul JAR Sanctuary embarqué, identique au JAR construit, sans monde ni
module de test. Le JAR de production inclut Story et aucune classe de son banc
client. Assets et données identiques à beta.233, hors les neuf traductions
ajoutées dans chacune des langues FR/EN ; les libellés existants sont conservés.
Reçu : `build/story234-mrpack-receipt.json`.
- JAR : `25dc161468679379e642f9746761905045d1135b6a300e3bc3f58f37a4c8f9a8`.
- MRpack : `0b16514e4dec16d14061fd25c7cb42d53fdb28c73f06a1c6361d16d059977c69`.
Les trois commits couvrent l'interface, les tests/documentation et la livraison.
Aucune publication distante, modification de canal packwiz, synchronisation
Prism ou ouverture de monde personnel effectuée.
+19
View File
@@ -0,0 +1,19 @@
# Écrire les histoires de Sanctuary
Story accueille des textes personnels sur Sanctuary, son développement, Steve,
Minecraft et ce que signifie habiter un jeu. Les numéros de 1 à 100 sont des
repères durables ; ils n'imposent ni un ordre de lecture ni une chronologie.
Copier [le modèle](TEMPLATE.md) dans un fichier nommé `001.md` à `100.md`, puis
remplacer le titre et écrire librement dans la section Texte. Les paragraphes,
les hésitations et la voix de l'auteur peuvent être conservés tels quels.
La section Idée de découverte est facultative et peut rester vide.
Transmettre les fichiers au fil des séances pour préparer les prochains tickets.
Ne pas renuméroter une histoire déjà intégrée. La traduction éventuelle des récits
se décide avec l'auteur ; les interfaces du jeu disposent de leurs libellés FR/EN.
En beta.234, les 100 histoires sont encore inconnues et désactivées. Ces fichiers
sont des sources de rédaction : le mod ne les charge pas automatiquement.
L'intégration des premiers textes et leurs conditions de découverte restent à
implémenter, avec autorité serveur si elles dépendent de la partie.
+12
View File
@@ -0,0 +1,12 @@
# Titre de l'histoire
Numéro : 001
## Texte
Écrire ici le texte, avec autant de paragraphes que nécessaire.
## Idée de découverte (facultative)
Décrire éventuellement un geste, une rencontre, un lieu ou une autre idée qui
pourrait révéler cette histoire. Cette note est une intention de conception.
+54 -1
View File
@@ -1,5 +1,58 @@
# Sanctuary Island — fil rouge de la refonte
## Retour au laboratoire — 1er octobre 2026
Le créateur demande une nouvelle visite avec la graine 0 pour décider si le
worldgen reste en pause. [WG-OPTIONS-195](worldgen-options-beta195.md) conserve
le terrain beta.193 et nettoie la liste de création : Sanctuary et les types
vanilla, sans variantes de labo visibles. Le menu sans Amis sera examiné à la
sortie du solo. Aucune nouvelle retouche de relief ni série de captures décidée.
Le choix d'intégrer le profil de labo à la génération publique reste ouvert.
## Reprise du 1er octobre 2026 — interfaces et usages
**Décision du créateur :** arrêter les séries de screenshots et les retouches
de génération, biomes et chunks. Le laboratoire beta.193 reste le dernier
état de comparaison, avec ses réserves visuelles documentées ; cette pause
ne vaut pas validation esthétique complète. Les priorités worldgen ci-dessous
sont désormais historiques.
**Premier lot demandé : [UI-194](main-menu-beta194.md).** Retirer Amis du menu
principal, rapprocher Options et Quitter de Solo/Multijoueur et conserver la
navigation clavier. Ce retrait figurait déjà dans le cadrage Storyquest initial.
**Proposition de suite à discuter, sans lancement implicite :**
| Sujet déjà envisagé | Premier résultat utile |
| --- | --- |
| Habitant | Une page claire pour l’identité, la progression et le familier, à partir des données réellement disponibles |
| Combat et Factions | Clarifier les accès aux épreuves, aux membres et aux projets communs ; distinguer les fonctions présentes des projets futurs |
| Storyquest | Choisir une première découverte reliée au SGA et à une activité existante, puis afficher sa piste et sa conséquence personnelle ou collective |
| Familiers et cuisine | Revoir l’utilité d’un passif existant selon le port sur la tête et choisir un goût à découvrir ; leur lien avec la préparation d’une sortie reste à concevoir |
Le prochain travail peut utiliser l’île et ses lieux actuels. Les expansions,
la nouvelle hydrologie et de nouvelles structures ne sont pas des dépendances
de cette reprise des menus. Aucun passif, nouvelle quête ou écran supplémentaire
n’est annoncé comme implémenté par UI-194.
## Historique du chantier terrain
**Après la visite beta.190 :** le créateur demande de revenir au relief d’avant
les plateaux et de retirer aussi leurs affleurements. [WG-RESTORE-191](restore-relief-beta191.md)
restaure la base beta.188 ; cavités, creux et pointes restent la direction,
avec des formations singulières ponctuelles plutôt qu’un traitement uniforme.
**Après la visite beta.189, 30 septembre :** [WG-NATURE-190](natural-refinement-beta190.md)
reprend le relief naturel et les cascades. Ruines et salle inférieure appréciées ;
le choix de la ressource renouvelable d’activation du portail reste ouvert.
Les terrasses ciselées sont réservées à une expansion future dans le backlog.
La rosace actuelle est à Y=640 et le palais supérieur à Y=1278 ; les paragraphes
antérieurs ci-dessous conservent l’historique de conception.
**Après la visite beta.181 :** palette naturelle validée ; dégager les huit
axes. Le [lot ORIGIN-182](origin-gallery-beta182.md) prépare la galerie
souterraine et la variante aérienne en rosace. L’origine reste à Y=320.
**Actualisation du 30 septembre :** relief et donjon beta.180 appréciés en
visite. Le [lot ORIGIN-181](origin-landmark-beta181.md) fixe le bloc originel
en **(0,320,0)** dans un petit repère aérien ouvert. Il conserve les demandes
@@ -211,7 +264,7 @@ en réserve. L'essai peut conduire à simplifier, déplacer ou abandonner une id
La lecture minimale d'une demande ou d'une découverte accompagne sa scène dans
les interfaces existantes. La refonte complète Habitant/Combat/Factions reste
dans la réserve ; elle se précisera avec les gestes réellement testés. Le
retrait demandé de Friends reste une petite tâche explicite à réaliser, sans
retrait demandé de Friends est traité dans [UI-194](main-menu-beta194.md), sans
en faire une dépendance de la carte de l'île.
Les navets, la loterie, le shop, l'ensemble des créatures, le chenil, les
+100
View File
@@ -0,0 +1,100 @@
# FINISH-189 — refuges au sol, berges et repères souterrains
Ticket du 30 septembre 2026, branche `codex/terrain-finish-beta189`.
Retour de visite beta.188 à partir des captures 19:55:33 et 19:57:00.
## Contrat
Nouveau preset `sanctuary_test:terrain_finish_v1`, profil `finish`, graine 42.
La partie beta.188 reste ouverte et préservée. Aucune migration ou régénération.
Corrections demandées : refuges qui suivent le sol, sédiments suivant la profondeur,
sable au-delà des berges, rejet des arbres dès leur plantation, reliefs étagés et
roche apparente. Accent sur le portail inférieur par le sol et la lumière.
Essais bornés : déversoirs vers une ouverture proche si le terrain l'autorise ;
petites ruines dans un volume de grotte sec déjà présent, sans excavation.
Pas de nouveau biome de glace. Une autre variante de lush cave reste à concevoir.
## Réalisation
Le relief n'est transformé qu'entre Y=252 et Y=316 par une fonction analytique,
sans nouveau bruit ni nouvelle passe d'hydrologie. Les grottes profondes et récifs
aériens gardent leur densité. Les affleurements suivent escarpements et épaules.
Les refuges de surface choisissent leur sol dans la densité, sans feuilles.
Les fonds passent du sable peu profond à l'argile des zones calmes, avec gravier
sur les ruptures de pente. Berges sableuses sur trois blocs au maximum et jusqu'à
deux blocs au-dessus de l'eau. Les plantations natives de type arbre et système
racinaire sont rejetées avant toute écriture près des étangs.
Le portail horizontal 5×5 avec vide 3×3 reste en place. Sol taillé et éclairage
en cuivre/pierres lumineuses soulignent le centre et les accès ; chandelier
suspendu au toit existant. Les petites ruines sont un prototype, pas une ville
avec habitants, commerce ou nouvelles quêtes.
## Vérifications
Les résultats finaux et leurs limites sont détaillés ci-dessous.
## Résultat vérifié — graine 42
- Huit ancres aux mêmes emplacements et orientations qu'en beta.188, offres
vérifiées et remises à leur état initial après le contrôle. Les surfaces des
refuges suivent la densité rocheuse, sans consulter la hauteur des feuilles.
- 1 120 blocs de sable sur les berges sèches ; fonds de 1 146 blocs de sable,
376 de gravier et 2 896 d'argile ; 408 plantations aquatiques. Zéro tronc dans
les colonnes des étangs et des plages contrôlées, de 28 blocs sous l'eau à
28 blocs au-dessus. Les arbres voisins peuvent conserver un surplomb de feuilles.
- Une cascade : départ (143,244,-147), déversoir (153,244,-147). Chenal de dix
blocs, entaille locale de treize blocs au total. Soixante-quatre blocs de chute
sont préremplis ; les fluides natifs poursuivent la chute vers le vide.
- Quatre ruines de cinq blocs de côté, aux sols (24,163,-64), (-8,147,-80),
(64,163,-80), (56,120,-80). Appuis rocheux contrôlés, zéro bloc de cavité
excavé. C'est un petit ensemble de vestiges étagés, pas une ville complète
ni un nouveau réseau de couloirs.
- Portail conservé en (0,175,0), bordure 5×5 et ouverture sèche 3×3. Sol de
pierre taillée, accès lumineux et chandelier : vingt sources lumineuses
supplémentaires dans ce plan, sans creuser de nouvelle salle.
- Sur le relevé du relief : 616 hauteurs de surface modifiées, quatre blocs
d'écart maximum ; 337 points d'affleurement. Les 25 205 échantillons de densité
des profondeurs et des récifs restent identiques. La compression conserve les
fines crêtes au lieu de les supprimer entre deux échantillons.
- Palais, 49 cartes verrouillées dans leurs 49 cadres horizontaux, gemmes,
soufre, butin en fer enchanté et passages du donjon contrôlés. Cartes et état
initial des ancres relus dans la copie destinée au solo.
Génération puis réouverture réussies : `build/finish189g-cold.json` et
`build/finish189g-warm.json`. Démarrage du serveur : 11,369 s / 0,581 s ; processus
prêt après l'ensemble des contrôles : 67,717 s / 19,973 s. Zéro région d'hydrologie.
Plans locaux des berges/déversoirs : 137 ms ; ruines : 459 ms à froid. Ce sont des
mesures de laboratoire, pas une garantie de durée identique sur chaque machine.
Le serveur de diagnostic désactive son watchdog : la vérification charge les
zones et remplit toutes les cartes dans un seul appel. Un premier contrôle a
atteint les 60 s pendant l'atlas. Le solo garde le remplissage progressif habituel
et ne lance pas cette batterie de mesures au démarrage.
`./gradlew check build assemblePack assembleTestPack` réussi en 9 min 1 s,
avec 265 GameTests réussis. Après les derniers correctifs du module de labo,
compilation/JAR ciblés, génération et réouverture natives réussies ; pack
optionnel resynchronisé. Ses 165 classes correspondent aux classes compilées
et le JAR distribué est identique : `build/finish189-pack-receipt.json`.
Aucune publication de canal, installation Prism ou ancienne sauvegarde modifiée.
## Visite
Nouvelle sauvegarde `Sanctuary-Terrain-Finish-189-Solo`, profil `finish`, run
`visite189`, graine 42. Vue 32, simulation 12, spectateur, commandes activées.
Solo Vulkan ouvert : connexion confirmée à 20:29:55, distances 32/12 et
masquage du palais depuis le sol confirmés dans `build/finish189-solo.log`.
- Étang ouest : `/tp -104.5 269 119.5 180 35`
- Ancre nord : `/tp 36.5 252 -168.5 180 0`
- Cascade : `/tp 158.5 248 -146.5 90 25`
- Portail inférieur : `/tp 0.5 179 10.5 180 20`
- Ruines : `/tp 24.5 167 -71.5 0 20`
Le jugement esthétique reste à faire pendant la nouvelle visite. La glace et
un biome supplémentaire ne sont pas ajoutés. Piste proposée pour plus tard :
une cavité claire de calcite et d'améthyste, plus calme que les jardins lush,
les marais et le soufre ; aucune décision d'implémentation à ce stade.
+4
View File
@@ -1,5 +1,9 @@
# UI-045 — menu principal
Contrat historique : [UI-194](main-menu-beta194.md) retire ensuite la ligne
Friends / Amis et rapproche les commandes restantes. Les essais ci-dessous
décrivent beta.045, pas le menu courant.
Branche `codex/title-menu-beta045`, à partir de beta.044.
## Contrat
+7
View File
@@ -1,5 +1,12 @@
# Sanctuary — vision du projet
**Cap du 1er octobre 2026 :** le créateur suspend les retouches du worldgen,
des biomes et des chunks ainsi que les tests de screenshots après beta.193.
La reprise porte sur les interfaces et les idées du Storyquest, avec le retrait
d’Amis du menu principal en premier. Voir le [fil rouge courant](storyquest-fil-rouge.md)
et [UI-194](main-menu-beta194.md). Les priorités de septembre ci-dessous
conservent l’historique ; elles ne relancent pas le chantier terrain.
**Direction courante — 29 septembre 2026 :** le
[fil rouge de la refonte](storyquest-fil-rouge.md) reprend **Sanctuary Island,
l'île de départ**, autour de plans géographiques indépendants et de parcours
+82
View File
@@ -0,0 +1,82 @@
# WG-219 — Plages basses et palmiers de l’Ouest
Branche `codex/west-beaches-beta219`, depuis beta.218 (`3adb08e`).
## Contrat
L’océan 218 est validé : conserver exactement le fond, la fracture, le temple,
les coraux et les épaves à graine identique. Abaisser les berges à la hauteur
de l’eau sur trois à quatre blocs, puis monter doucement. Concentrer beaucoup
de palmiers sur cette plage intérieure, retirer ceux du bord extérieur.
Retirer soufre, cinabre, pointes, sources et biome sulfureux de la couronne Ouest.
Ne pas retirer le soufre des autres régions de Sanctuary.
Nouveaux profils 219 Small/Medium/Large ; historiques conservés, aucun monde
ancien modifié ou régénéré. Contrat d’essai : mondes jetables neufs 42/0,
activation de l’ancre Ouest, interruption/reprise. MRpack local et nouvelle
visite Vulkan 32 chunks. Aucun push, tag, canal public ou mise à jour Prism.
## État
Implémentation et vérifications terminées. MRpack local vérifié ; rendu des
nouvelles berges à apprécier en jeu.
## Mise en œuvre
Le champ océanique 218 est partagé : aucune modification sous l’eau, mêmes
biomes de récif et de fosse. Les sites des quatre épaves sont repris du calcul
historique avec sa séquence aléatoire, indépendamment des nouveaux palmiers.
Le plan temporaire est libéré ; seuls les quatre emplacements sont conservés.
Sur la terre sèche, une bande de sable reste à Y=220 sur environ quatre blocs,
au lieu de démarrer à Y=221. Première marche ensuite, puis une montée étalée
vers de petites hauteurs. Les fondations de l’arrivée et du relais gardent
leurs positions. La cuve et son dessous restent fermés.
Les palmiers suivent le contour intérieur à 0,7–4,2 blocs du rivage calculé,
sur le sable à Y=220, avec variations de hauteur, inclinaison et espacement.
Pas de palmiers sur la couronne extérieure. La terre intérieure conserve une
végétation basse. Soufre, cinabre, pointes, sources et biome sulfureux retirés
uniquement de l’Ouest 219 ; les anciens mondes et les autres régions conservent
leurs matériaux.
## Vérifications du 5 octobre 2026
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,west218,west219 -PsanctuaryAtlasOnly=true` :
réussi, six GameTests obligatoires passés. Contrôles de terrain sur six graines :
fond, matériaux immergés et biomes marins identiques à 218 ; plage basse,
première montée, palmiers et absence de matériaux sulfureux vérifiés.
Les profils historiques restent disponibles, dont les trois tailles 218.
Essais natifs sur deux nouveaux mondes Small, avec activation Ouest,
interruption à 0/94 chunks puis reprise jusqu’à READY :
| Graine du monde | Centre Ouest | Graine de l’expansion | Palmiers planifiés | Colonnes de plage vérifiées | Épaves / coffres |
| --- | --- | --- | --- | --- | --- |
| 42 | −960, 0 | −8263140775942472950 | 431 | 1510 | 4 / 12 |
| 0 | −944, 128 | −189784416336457674 | 431 | 1256 | 4 / 12 |
Huit troncs contrôlés physiquement sur chaque monde, zéro geyser. Monument,
relais et falaises vérifiés ; 94 chunks préparés dans chaque cas. Les essais
natifs portent sur Small ; Medium/Large sont assemblés avec les mêmes règles
d’expansion, sans visite native supplémentaire sur cette livraison.
MRpack : `build/Sanctuary-beta.219.mrpack`, également copié dans Downloads.
Archive intègre, JAR strictement identique au build, version 219,
profils historiques et trois tailles présents ; aucun monde ni module de test.
SHA-256 : `9be5755c0f53f33988c07cf8e979c02bd6bb137bf4565502a24545ab19201042`.
JAR SHA-256 : `4265e78a203a3bd950771233c337e125c0aaed7080da526d1b8a749c4c25dc02`.
Traces locales : `build/west219-build-ready.log`,
`build/worldgen-lab/west219-final/small/42/{cold,warm}.json`,
`build/worldgen-lab/west219-final0/small/0/{cold,warm}.json` et
`build/west219-mrpack-receipt.json`. Aucun monde existant migré ou régénéré.
Visite neuve `Sanctuary-West-219-42` ouverte à 15:16:09 (Europe/Paris),
Vulkan/MoltenVK, vue 32 chunks, simulation 5, créatif et commandes activés.
L’ancienne visite 218 a été arrêtée proprement et sa sauvegarde conservée.
La nouvelle visite est une copie du monde de vérification 42 arrêté ;
`WEST219_VISIT_OPEN` confirmé dans le journal. Aucun essai graphique OpenGL.
Les mesures vérifient le placement ; l’appréciation visuelle des nouvelles
berges et de la densité des palmiers reste au joueur.
+86
View File
@@ -0,0 +1,86 @@
# WG-220 — Couronne vivante et plages libres de l’Ouest
Branche `codex/west-living-rim-beta220`, depuis beta.219 (`988a6c8`).
## Contrat
Conserver l’océan validé : eau, fond marin, fracture, monument et épaves.
Élargir la plage basse à 12–15 blocs libres ; déplacer les palmiers en retrait.
Rendre la couronne extérieure irrégulière par du relief et des creusements 3D,
avec ravins et surplombs. Garder une paroi pleine entre ces creusements et l’eau.
Sur l’herbe : arbres, buissons, fleurs. Sur le sable : cactus, bois mort,
buissons secs et herbes jaunes. Soufre et cinabre restent absents de cet Ouest.
Nouveaux profils 220 Small/Medium/Large, historiques conservés. Aucun monde
ancien modifié ou régénéré. Contrat d’essai : mondes jetables neufs 42/0,
activation de l’ancre Ouest et interruption/reprise. MRpack local et visite
Vulkan 32 chunks. Aucun push, tag, canal public ou déploiement Prism.
## État
Implémentation et vérifications terminées ; rendu du pourtour à apprécier en jeu.
## Mise en œuvre
Le champ marin 218/219 est repris sans changement pour toutes les colonnes
immergées. Seules les colonnes terrestres reçoivent le nouveau champ 220 :
largeur de plage variable de 12 à 15 blocs, puis reliefs, creux et ravins.
La limite extérieure et les surplombs varient en trois dimensions ; des
cavités s’ouvrent dans la couronne. Les 22 premiers blocs depuis la rive
gardent une paroi pleine sous le niveau marin. Arrivée et relais conservent
leurs fondations et positions.
Le sol utilisable est recherché dans la densité finale, puis mis en cache
par colonne. Les sables et sols meubles ne coiffent que des surfaces soutenues.
Les palmiers commencent en retrait à partir de 28 blocs de la rive ; aucun
bloc de végétation n’empiète sur les 17 premiers blocs. Les bosquets combinent
palmiers, chênes et buissons, fleurs par taches et herbes. Les zones sableuses
reçoivent cactus, arbres morts en chêne écorcé, buissons et herbes sèches.
Chaque décor est admis entièrement dans l’air du terrain final avant sa pose
par chunk ; les emplacements sont déterministes et calculés une fois.
## Vérifications du 5 octobre 2026
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,west219,west220 -PsanctuaryAtlasOnly=true` :
réussi ; cinq GameTests obligatoires passés. Le contrôle 220 couvre six graines :
0, 42, −6763683964522674921, 3285501279717306940,
−8263140775942472950 et −189784416336457674. Comparaison des états immergés
avec 219, plage libre, paroi pleine, creux et hauteurs, cavités, sable soutenu,
végétation variée en retrait, déterminisme et positions des structures.
Les trois réglages de bruit de l’île principale sont identiques à 219 ;
les anciens profils sont conservés.
MRpack intègre : JAR identique au build, profils historiques et trois tailles
présents, aucun monde ni module de test. Copie dans Downloads.
SHA-256 MRpack : `a7f176e18041ac5bcc764ca0461e22551e08743af7475fc53bc156c18f8299d2`.
SHA-256 JAR : `cf1352ed4d7d1c1a9f8582986b64befef1be91184fe7dc4259dff9f46f005c66`.
Traces locales : `build/west220-build-ready.log` et
`build/west220-mrpack-receipt.json`.
Essais natifs Small sur les graines 42 et 0 : activation de l’ancre Ouest,
interruption à 0/94 chunks et reprise réussies. Expansion de 1024 blocs,
94 chunks de préparation dans chaque cas. Aucune migration d’ancien monde.
| Graine | Centre Ouest | Graine de l’expansion | Palmiers en retrait | Colonnes de plage vérifiées |
| --- | --- | --- | --- | --- |
| 42 | −960, 0 | −8263140775942472950 | 235 | 3207 |
| 0 | −944, 128 | −189784416336457674 | 246 | 2688 |
Sur chaque monde : huit troncs de palmier et 21 décors de sept catégories
contrôlés physiquement, survie native des plantes vérifiée. Quatre épaves et
douze coffres de butin, monument complet et relais fonctionnel conservés.
Falaises immergées et eau contrôlées. Les essais de volume comparent le terrain
marin ; ils ne garantissent pas un placement identique de chaque corail natif.
La nouvelle végétation et la silhouette extérieure restent à apprécier en jeu.
Medium/Large sont assemblés avec les mêmes règles d’expansion, sans nouvelle
visite native de ces tailles pour cette livraison.
Traces : `build/worldgen-lab/west220-final/small/42/{cold,warm}.json` et
`build/worldgen-lab/west220-final0/small/0/{cold,warm}.json`.
Nouvelle visite `Sanctuary-West-220-42` ouverte le 5 octobre à 16:08:19
(Europe/Paris), Vulkan/MoltenVK, 32 chunks, simulation 5, créatif avec vol et
commandes. Copie du monde de vérification 42 arrêté ; anciennes sauvegardes
conservées. Confirmation `WEST220_VISIT_OPEN` dans le journal client.
Pas de validation visuelle anticipée ni de test OpenGL.
+118
View File
@@ -0,0 +1,118 @@
# WG-218 — Plateau sous-marin et oasis de l’Ouest
Branche `codex/west-oasis-beta218`, depuis beta.217 (`f8456df`).
## Contrat
Océan Ouest de 1024 blocs : plateau sous-marin, falaises irrégulières vers
une fracture centrale et monument océanique obligatoire au centre.
Suppression des racines ; couronne de plages de sable et grès, végétation,
palmiers, biomes de soufre avec cinabre et épaves natives. Aucune calcite
sur ce nouvel Ouest. Conserver l’île principale, le Nord et le Sud.
Nouveaux profils 218 Small/Medium/Large uniquement ; profils historiques
conservés. Aucun monde existant modifié ou régénéré. Contrat d’essai : mondes
jetables neufs 42 et 0, activation de l’ancre Ouest, interruption et reprise.
Préparation limitée aux destinations utiles ; aucune hydrologie globale.
Livraison locale MRpack et visite Vulkan 32 chunks. Aucun push, tag, canal
public ou installation Prism à modifier.
## État
Implémenté ; compilation, sept GameTests et essais natifs 42/0 réussis.
MRpack local vérifié. Le rendu reste à apprécier dans la nouvelle visite.
## Mise en œuvre
Eau à Y=220 ; plateau sableux généralement vers Y=198–206, rupture étroite
vers une fosse allongée, sinueuse et orientée par la graine. Fondation centrale
du monument à Y=136. Le dessous de la cuve reste sous le point le plus profond,
indépendamment des changements de hauteur du fond : une falaise ne peut plus
passer sous le dessous de sa voisine. Bruit 3D sur le dessous et le bord externe,
avec une enveloppe protégée autour de l’eau. Aucune racine ajoutée.
Couronne de grès et plages sableuses, herbe et palmiers à troncs courbés,
frondes de jungle persistantes. Trois grands secteurs irréguliers de soufre,
cinabre en veines, pointes natives et petites sources de soufre actif. Cinq
biomes versionnés isolent cette écologie des autres expansions. Pas de calcite
ni de terracotta dans le nouveau terrain ; grès aussi sur les finitions du relais.
Quatre épaves natives variées sont placées sur les hauts-fonds autour de la
fosse, avec les tables de butin natives. Leur altitude est fixée par le champ
avant décoration, pour ne pas dépendre du premier chunk chargé. Plans de
végétation et structures déterministes, placement découpé par chunk. Le temple
conserve son graphe de salles et ses trois gardiens anciens ; pas de nouveau
StructureStart, donc la limitation de localisation et de réapparition native
des gardiens ordinaires de 217 reste applicable.
La préparation avant READY reste bornée à l’arrivée, au temple et au relais.
Les épaves et la végétation apparaissent à l’exploration. Aucun scan hydrologique
mondial ou calcul de trajet de rivière.
## Vérifications
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,west217,west218 -PsanctuaryAtlasOnly=true` réussit :
contrôles purs et sept GameTests. Le premier passage avait un mauvais nom de
climat dans un test de conservation du Nord ; corrigé en `glacial`.
Le contrôle géométrique couvre six graines, les fondations du monument, les
parois sous-marines sur toute leur hauteur, les plages et les secteurs
sulfureux, la reproductibilité des détails et l’isolement des profils 217/218.
Les trois fichiers de bruit de l’île principale sont identiques à ceux de 217.
Deux ajustements ont concerné uniquement le diagnostic natif, sans changer le
JAR distribué : huit chunks côtiers trop peu profonds ne suffisaient pas à
relever les coraux de 42 (présents dans sept chunks voisins sauvegardés) ;
le relevé utilise seize points plus profonds. Une recherche de falaise s’arrêtait
à 70 blocs du centre, trop tôt pour un bras étroit de la fracture de 42 ; elle
va désormais jusqu’au centre. Chaque nouvel essai utilise un dossier neuf.
Essais terminés : `west218-delivery` (42) et `west218-final0` (0), avec le même
JAR Sanctuary issu du build réussi. La dernière extension de recherche du
contrôle des falaises ne modifie que le module Test. Activation par l’ancre
Ouest, paiement exact, refus du doublon, interruption à 0/94 et reprise READY.
| Relevé | Graine 42 | Graine 0 |
| --- | ---: | ---: |
| Graine dérivée | -8263140775942472950 | -189784416336457674 |
| Chunks préparés | 94 | 94 |
| Palmiers planifiés | 294 | 307 |
| Pointes de soufre | 198 | 207 |
| Sources géothermales | 17 | 18 |
| Cinabre dans les échantillons | 3176 | 2660 |
| Épaves / coffres de butin | 4 / 12 | 4 / 12 |
| Coraux dans seize chunks | 24 | 124 |
| Or du temple | 8 | 8 |
| Gardiens anciens sauvegardés | 3 | 3 |
| Blocs du relais comparés au plan | 2069 | 2069 |
Temple 42 : `(−960, 137, 0)` ; relais `(−1355, 238, 0)`.
Temple 0 : `(−944, 137, 128)` ; relais `(−1341, 238, 128)`.
Les trois gardiens sont relus dans les fichiers d’entités après arrêt.
Contrôle complémentaire des chunks sauvegardés entre Y=112 et Y=220 :
727 chunks / 433 820 interfaces eau/autre sur 42 ; 703 / 431 123 sur 0.
Aucune ouverture d’une colonne d’eau vers le vide inférieur dans les données
contrôlées. Quelques poches d’air fermées subsistent près des structures et
de la décoration native (55 cellules sur 42, groupes de cinq au maximum ;
21 sur 0, groupes de trois au maximum). Le volume intérieur du monument et
les chunks absents ou incomplets sont exclus ; ce contrôle ne représente pas
une prégénération de toute l’expansion. Reçus ignorés : `build/west218-water42.json`
et `build/west218-water0.json`. Aucun benchmark de fluidité ou essai Windows.
## Livraison locale
MRpack normal Small/Medium/Large, sans module Test ni sauvegarde,
copié dans `/Users/koka/Downloads/Sanctuary-beta.218.mrpack`.
Intégrité ZIP, version, profils historiques et identité exacte du JAR vérifiées.
SHA-256 MRpack : `feecc10ca1f5873bc795a683f5d31cb5b7ad5d6484e4880cdec0841318b4d9ee`.
SHA-256 JAR : `feddc40854c3a1c8b321426f1007e967498b11c287dc28604ed0b3bfda03318a`.
Visite neuve `west218-visit`, monde `Sanctuary-West-218-42`, copie du monde
vérifié et arrêté. Créatif, commandes, vol, vue 32 chunks et simulation 5 ;
départ `(−564, 269, 0)` vers le centre de la mer. Aucun ancien monde modifié.
Ouverture confirmée le 5 octobre 2026 à 14:51:30 CEST par
`WEST218_VISIT_OPEN` ; backend Vulkan/MoltenVK et options 32/5 confirmés.
Aucun push, tag, canal packwiz public ou instance Prism modifié.
+114
View File
@@ -0,0 +1,114 @@
# WG-217 — Mer suspendue de l’Ouest
Branche `codex/west-ocean-beta217`, depuis beta.216 (`0eb4517`).
## Contrat
Prototype jouable : mer de diamètre nominal 1024, cuve rocheuse étanche,
ramifications minérales depuis l’intérieur vers le vide et déformation 3D.
Bords clairs et ocres inspirés de Yellowstone, hauts-fonds et coraux.
Un monument océanique natif obligatoire, avec fondation et profondeur réservées
dans le calcul du terrain. Relais régional visible sur la rive extérieure.
Nouveaux profils 217 Small/Medium/Large uniquement ; anciens profils, île
principale, Nord et Sud conservés. Aucun monde existant modifié ou régénéré.
Contrat d’essai : mondes jetables neufs sur les graines 42 et 0, activation
par l’ancre Ouest, interruption et reprise autorisées. Préparation limitée aux
lieux utiles, sans hydrologie globale ni génération préalable de toute la mer.
MRpack local et nouvelle visite solo Vulkan à 32 chunks. Aucun push, canal
public ni mise à jour de Prism.
## État
Implémenté, contrôles réussis et MRpack vérifié. Nouvelle visite Vulkan ouverte ;
le rendu reste à apprécier en jeu.
## Mise en œuvre
La mer utilise un champ géographique déterministe commun au terrain, aux
biomes et au placement du temple. Eau à Y=220, fond variable et hauts-fonds
sur les racines sous-marines ; 9 à 12 départs de racines bifurquent vers le
vide. Deux bruits 3D irrégularisent les volumes extérieurs et un troisième
ouvre des cavités au-delà du collier étanche. Les rives mêlent calcite,
grès, touches de terracotta et roche. Pas de simulation hydrologique globale :
les sources d’eau sont posées localement pendant la génération des chunks.
Le temple reprend le graphe de salles du monument océanique Minecraft 26.3,
son trésor, ses éponges éventuelles et ses gardiens anciens. Le champ réserve
une fondation à Y=153 et une profondeur suffisante, quelle que soit la graine.
La pièce extérieure **et** ses salles internes sont translatées ensemble.
Placement déterministe, découpé par chunk, comme le manoir régional existant.
Cette première implantation ne crée pas de StructureStart natif : pas de
localisation vanilla ni de zone native de réapparition des gardiens ordinaires.
Trois biomes isolés reprennent l’ambiance et la végétation sous-marine natives,
sans carvers, minerais génériques ou sources d’eau susceptibles de percer la
cuve. Le monument et le relais sont préparés avant l’annonce SGA ; le reste
de la mer se génère à l’approche. Le relais reprend le socle régional en
prismarine/calcite et pointe vers l’Ouest. Les générations ultérieures de ce
relais utilisent encore la même famille océanique dans ce prototype ; la
variété des expéditions lointaines reste un chantier séparé.
## Vérifications et essais
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,west217 -PsanctuaryAtlasOnly=true` réussit :
contrôles purs et cinq GameTests. La passe précédente a également validé les
contrôles ciblés des relais 215 et du Sud 216. Les trois fichiers de bruit 217
sont identiques aux 216 ; les préréglages n’ajoutent que la nouvelle révision
et les trois biomes de l’Ouest. Libellés FR/EN présents.
Le premier contrôle a trouvé que l’aplanissement de l’arrivée empiétait sur
la mer : cette modification du sol est désormais limitée à la rive sèche.
Le premier relevé natif cherchait huit blocs d’eau sur chaque rayon ; les
racines donnent parfois des récifs à cinq blocs de profondeur. Le relevé
côtier a été corrigé pour inclure ces hauts-fonds, sans changer le terrain.
Seul le module Test a été recompilé après le build final ; le JAR distribué
reste exactement celui du `check build` réussi.
Essais définitifs : `west217-verified` sur 42 et `west217-verified0` sur 0.
Activation par l’ancre Ouest, paiement exact, refus du doublon, interruption
à 0/83 puis reprise jusqu’à READY. Pas d’activation sur une sauvegarde antérieure.
| Relevé natif | Graine 42 | Graine 0 |
| --- | ---: | ---: |
| Centre X/Z | −960 / 0 | −944 / 128 |
| Graine dérivée | −8263140775942472950 | −189784416336457674 |
| Chunks préparés avant READY | 83 | 83 |
| Segments de racines | 33 | 27 |
| Colonnes côtières contrôlées en jeu | 2 048 | 2 048 |
| Coraux dans ces huit chunks | 5 | 20 |
| Blocs de prismarine du temple | 13 096 | 13 135 |
| Lanternes marines | 124 | 118 |
| Blocs d’or | 8 | 8 |
| Gardiens anciens dans les fichiers sauvegardés | 3 | 3 |
| Blocs du relais comparés au plan | 2 069 | 2 069 |
Temple 42 : `(−954, 154, −29)`, relais `(−1351, 244, 0)`.
Temple 0 : `(−980, 154, 138)`, relais `(−1343, 244, 128)`.
Les trois gardiens de chaque temple sont relus dans les fichiers d’entités
après arrêt du serveur. Les rapports couvrent la préparation utile et des
échantillons du littoral ; ils ne constituent ni une prégénération complète,
ni un benchmark de performances, ni un essai Windows, ni une validation visuelle.
## Livraison locale
MRpack normal avec Small, Medium et Large, aucun module Test ni monde :
`build/Sanctuary-beta.217.mrpack`, copié dans Downloads. Intégrité ZIP,
version, profils historiques et identité exacte du JAR vérifiées.
SHA-256 MRpack : `1244b296efb4c10da2286d5764cf311201f23a73b72c046b997255532acad386`.
SHA-256 JAR : `d39bdc865a23bf605197b5672dfe5a5cff9cfbc7c9b4ad3a49125e331b86b6b5`.
Visite neuve `west217-visit-final`, monde `Sanctuary-West-217-42`, copie du
monde vérifié, créatif avec commandes et vol. Vue 32 chunks, simulation 5,
départ `(−576, 275, 0)` face à la mer. Ouverture confirmée le 5 octobre 2026
à 14:11:06 CEST par `WEST217_VISIT_OPEN` ; backend Vulkan/MoltenVK confirmé.
Aucun canal public, tag ou installation Prism mis à jour.
Lecture complémentaire des chunks sauvegardés à Y=220 : 55 808 colonnes et
1 142 contacts eau/rive contrôlés sur 42 ; 55 040 colonnes et 1 371 contacts
sur 0. Aucun contact latéral eau/air trouvé dans les chunks dont le terrain
est disponible. Les chunks absents ou incomplets sont exclus, sans extrapoler
ce relevé à toute l’expansion. Reçus ignorés : `build/west217-water42.json`
et `build/west217-water0.json`.
+95
View File
@@ -0,0 +1,95 @@
# WG-221 — Pierre jaune et parois de l’Ouest
Branche `codex/west-yellow-stone-beta221`, depuis beta.220 (`58aa4c2`).
## Contrat
Retirer les arbres morts en bois écorcé et la passe de ravins de 220.
Conserver le modelé 3D, avec un Voronoi discret pour former des parois plus
droites. Agrandir les zones de sol cohérentes et réserver sable/herbe aux
surfaces douces ; nouvelle pierre jaune pour les masses rocheuses.
Nouveau bloc `sanctuary:yellow_stone`, mineable, ramassable et constructible,
libellés FR/EN, juste après Stone dans les onglets Naturel et Construction.
Première apparence : grain de la stone native et teinte jaune
grès appliquée par le système de couleurs natif, sans nouvelle texture lourde.
Océan, monument, épaves, plage libre de 12–15 blocs et végétation vivante conservés.
Nouveaux profils 221 Small/Medium/Large uniquement ; anciens profils et mondes
conservés. Contrat d’essai : mondes jetables neufs 42/0, activation Ouest et
interruption/reprise. MRpack local et visite Vulkan 32 chunks. Aucun push,
tag, canal public ou déploiement Prism.
## État
Implémentation et vérifications terminées ; nouveau rendu à apprécier en jeu.
## Mise en œuvre
Le profil 221 enlève la soustraction de 39 blocs qui formait les ravins de 220.
Le volume 3D, les cavités et les surplombs sont conservés. Des cellules Voronoi
de 76 blocs apportent 35 % du relief terrestre ; les raccords sont adoucis sur
quatre blocs et le bruit de surface est atténué près de leurs limites. Il n’y
a pas de découpage global par étages. Calcul et recherche du sol final restent
mis en cache par colonne ; seules les terres sèches utilisent cette passe.
La couverture végétale varie sur 135 blocs, au lieu de la superposition de
bruits à 49 et 13 blocs. Les surfaces trop pentues et les surplombs restent
en pierre jaune ; la terre et le sable occupent les parties suffisamment
douces et soutenues. Arbres écorcés supprimés du nouveau plan. Palmiers,
chênes feuillus, petits buissons, fleurs, cactus et herbes sèches conservés.
La nouvelle pierre utilise les propriétés physiques et sons de la stone,
la teinte cartographique du sable et le tag de minage à la pioche. Elle se
ramasse elle-même, possède un BlockItem et les noms « Pierre jaune » /
« Yellow Stone ». Teinte de bloc, particules et inventaire : `#F5D890` sur
le grain natif de stone, avec six faces et rotations du modèle. Les actifs
sont fournis par le mod ; aucune dépendance à un pack externe ni texture
PNG supplémentaire. Cette première pierre n’ajoute pas de variantes taillées.
## Vérifications du 5 octobre 2026
`./gradlew check build assemblePack assembleTestPack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=base204,west220,west221 -PsanctuaryAtlasOnly=true` :
réussi, six GameTests obligatoires passés. Le contrôle 221 couvre les graines
0, 42, −6763683964522674921, 3285501279717306940,
−8263140775942472950 et −189784416336457674. Volume marin comparé à 220,
réduction des creux de ravins et des transitions de couverture, présence des
cavités 3D, roche jaune et végétation, absence de bois écorcé, plage libre et
positions des structures conservées. Ancien profil 220 vérifié séparément.
Le second test vérifie la pioche en bois, le butin exact du bloc, son BlockItem
et la reconstruction des deux onglets créatifs natifs avec Pierre jaune juste
après Stone. Les libellés FR/EN, modèle à six faces teintées, modèle d’inventaire,
tag pioche et table de butin sont également vérifiés dans le JAR livré.
MRpack intègre, JAR identique au build, profils historiques et trois tailles
présents ; aucun monde ni module de test. Copie dans Downloads.
SHA-256 MRpack : `9128cdb4640cdf1bba81ee64bd6998c39bf0b7aaa07617440f946c1983c53024`.
SHA-256 JAR : `cc91b110c7289da152929d4a3ddd9110015d1f100c1071067954a476e308a3f0`.
Traces : `build/west221-build.log`, `build/west221-mrpack-receipt.json`.
Essais natifs Small sur 42 et 0 : activation Ouest, interruption à 0/94 chunks
et reprise jusqu’à READY réussies, 94 chunks préparés par expansion de 1024.
| Graine | Centre Ouest | Graine de l’expansion | Palmiers | Colonnes de plage contrôlées | Blocs de pierre jaune contrôlés |
| --- | --- | --- | --- | --- | --- |
| 42 | −960, 0 | −8263140775942472950 | 212 | 3207 | 63 |
| 0 | −944, 128 | −189784416336457674 | 181 | 2688 | 61 |
Huit troncs et 18 décors de six catégories inspectés physiquement par monde,
survie native des plantes vérifiée, aucun bois écorcé dans les plans. Monument,
relais, quatre épaves et douze coffres conservés ; eau et falaises immergées
contrôlées. Le terrain marin est comparé, pas la position exacte de chaque
corail natif. Medium/Large sont assemblés mais n’ont pas reçu de nouvelle
visite native pour cette livraison. Aucun ancien monde modifié ou régénéré.
Rapports : `build/worldgen-lab/west221-final/small/42/{cold,warm}.json` et
`build/worldgen-lab/west221-final0/small/0/{cold,warm}.json`.
Visite neuve `Sanctuary-West-221-42` ouverte le 5 octobre 2026 à 16:31:00,
Vulkan, distance 32 chunks et simulation 5, créatif/vol/commandes. Le client
vérifie les six faces teintées et la texture stone native :
`YELLOW_STONE221_CLIENT_PASS faces=6 tint=fff5d890`, puis
`WEST221_VISIT_OPEN`. Cela valide le chargement du modèle, pas une appréciation
visuelle des nouvelles parois. Trace :
`build/worldgen-lab/west221-visit/small/42/client/logs/latest.log`.
+167
View File
@@ -0,0 +1,167 @@
# WG-CONTINUITY-193 — raccordements et visites sur plusieurs graines
Branche `codex/worldgen-continuity-beta193`, Minecraft 26.3.
Nouveau profil de laboratoire `coherent`, mondes neufs uniquement.
Graines vérifiées : 42 (référence des retours), 2026 et 8675309.
## Demande
Conserver la direction des montagnes appréciée en beta.192 et corriger les
raccordements d’eau, le damier de mousse des ancres et les longues marches.
Vérifier plusieurs graines et examiner des captures réelles du jeu avant de
préparer la prochaine visite. La quantité globale de roche n’est pas à réduire
systématiquement ; la réserve précédente du créateur demeure.
## Contrat de cette itération
- Propriété commune des espaces remplis d’eau : éviter les nappes indépendantes
qui se recoupent à des hauteurs différentes dans une même cavité.
- Ancres de surface et aériennes adaptées à la densité du terrain, sans fond
ondulé artificiel ni damier de mousse ; conserver secteurs et orientation.
- Éviter les sols de grotte en plein air et interrompre localement les longues
marches du massif sans remettre des niveaux périodiques sur toute l’île.
- Ajouter des contrôles de raccordement, pas seulement de nombre de blocs.
- Produire des captures Vulkan de bassins, d’ancres et du relief dans des mondes
de diagnostic neufs, avec graine, position et version identifiées.
Aucune modification, régénération ou migration des sauvegardes précédentes.
Le profil beta.192 reste disponible avec son comportement antérieur.
## Changements de génération
Les volumes des étangs de surface évitent désormais les volumes déjà retenus
dans les cavités. L’eau est posée avant la décoration et ses colonnes sont
protégées contre les arbres et systèmes de racines. Les contrôles comptent
chaque cellule humide prévue, y compris celles que l’ancien contrôle ignorait
quand un autre bloc avait remplacé l’eau. Les berges sableuses débordent moins
haut et moins loin sur les flancs raides.
Les ancres aériennes utilisent le même relevé de sol que les ancres de surface.
Le chemin suit les colonnes réelles ; son admission refuse les sauts de hauteur.
L’herbe reprend la couleur du biome et la terre remplace le damier de mousse.
Les grottes gardent leurs palettes ; au-dessus de Y=240, une couverture rocheuse
locale doit réellement exister pour attribuer une palette de grotte.
Le massif 192 reste la base. De petites entailles irrégulières interrompent ses
contours, sans paliers périodiques ni modification des densités profondes et
aériennes. Les cerisiers cherchent un emplacement sec et dégagé près des
sommets choisis ; leur altitude suit le relief de la graine.
Les essais ont aussi révélé des collisions anciennes : la galerie choisit ses
salles secondaires dans des cavités voisines séparées de la pièce centrale.
Elle conserve seulement les salles admises, avec leurs liaisons praticables.
Les bassins évitent cette galerie et peuvent être moins nombreux si l’espace
manque. Les ruines évitent son volume et les geysers évitent les ruines.
Ces recherches restent bornées et leurs plans sont mis en cache ; aucun solveur
d’hydrologie régionale ni simulation permanente n’est ajouté.
## Méthode de comparaison
Le script `scripts/worldgen_lab.py verify --profile coherent --seed 42 --run NOM`
crée un laboratoire neuf, vérifie les blocs natifs, le ferme puis le rouvre.
Répéter avec 2026 et 8675309 ; les journaux et JSON restent dans leurs dossiers.
Une modification du code ou des données impose un nouveau nom d’expérience.
`scripts/worldgen_photos.py` prépare ensuite une copie neuve du monde vérifié,
un plan de caméras et un fichier de provenance. Il requiert `nbtlib`, `--source-run`,
`--seed`, `--run` et `--previous-client` (dossier client d’un ancien labo fermé).
La commande `worldgen_lab.py solo --profile coherent --seed GRAINE --run PHOTOS
--photo-plan CHEMIN/cameras.json` prend les images avec le moteur Vulkan du jeu.
Le mode photo refuse les sauvegardes qui ne portent pas le préfixe réservé
`Sanctuary-Photo-193-`. Il masque l’interface, attend le rendu des sections,
conserve une heure de midi fixe, capture puis ferme proprement le client.
Sans cette option, le solo reste une visite manuelle normale.
Les positions viennent des aménagements réellement générés : chaque bassin,
deux côtés du massif, les ancres aériennes et une ancre de surface. Une capture
réussie doit être examinée visuellement ; un nombre de blocs correct ne valide
ni la beauté des rives ni la silhouette du relief.
## Résultats
Génération et réouverture natives réussies pour les trois graines dans les
runs `coherent193k42`, `coherent193k2026` et `coherent193k8675309`.
Les plans d’eau, emplacements des ancres et relevés de relief sont identiques
après rechargement (`build/coherent193-three-seeds.json`).
| Graine | Volumes d’eau contrôlés | Cellules humides | Salles de galerie | Coffres de ruines |
| --- | ---: | ---: | ---: | ---: |
| 42 | 5 | 28212 | 3 | 4 |
| 2026 | 5 | 21542 | 3 | 3 |
| 8675309 | 4 | 8929 | 2 | 4 |
Sur chaque graine : zéro contact entre volumes indépendants, toutes les cellules
prévues encore humides, huit ancres contrôlées en blocs réels, aucun damier de
mousse dans leurs plans exposés, trois cerisiers réellement présents et 39 366
échantillons profonds/aériens inchangés. Le donjon, les gemmes, la galerie, le
soufre, les ruines, la rosace et les 49 cartes/cadres de l’ISS passent aussi les
contrôles natifs. La graine 42 admet un déversoir large de cinq colonnes ; les
deux autres gardent leurs bassins fermés quand aucun déversoir proche n’est admis.
Démarrages à froid : 15,2 / 18,9 / 19,1 s ; réouvertures : 0,6 / 0,7 / 1,0 s.
Zéro région d’hydrologie lourde. Avec l’ensemble des diagnostics et de l’atlas,
les essais à froid durent 112 / 188 / 106 s. Les processus tournaient en partie
en parallèle ; ce ne sont pas des benchmarks isolés et le solo ne rejoue pas
ces contrôles exhaustifs à chaque ouverture.
`./gradlew check build assemblePack assembleTestPack` réussi, 265 GameTests.
Le premier passage avait échoué sur le déplacement d’un familier volant, sans
modification de ce système ; la relance a passé les 265 tests. Après les derniers
ajustements du laboratoire, `:sanctuary-test:check :sanctuary-test:build` et le
réassemblage du pack de test ont réussi. 179 classes et 124 ressources du JAR
sont identiques aux sorties courantes et le JAR distribué correspond octet pour
octet (`build/coherent193-pack-receipt.json`). Pas de publication ni de mise à
jour de Prism.
## Examen des captures
La série retenue rassemble 29 PNG natifs 2560 × 1440 : 10 pour 42 dans
`photos193d`, 10 pour 2026 dans `photos193c` et 9 pour 8675309 dans `photos193e`.
Les dossiers sont sous `build/worldgen-lab/RUN/coherent/GRAINE/` ; les positions,
l’empreinte des sources et les empreintes des PNG sont conservées dans
`photo-provenance.json`. Galerie locale : `build/worldgen193-gallery/index.html`.
Les premières images nocturnes de 42 et pluvieuses de 8675309 sont conservées
comme diagnostics, hors de la galerie finale. Les services de temps réel et de météo quotidienne sont désactivés dans les
seuls clients photo jetables ; le script prépare également une longue période
de temps clair natif. La météo quotidienne avait rétabli la pluie après un
premier essai avec seulement les durées natives modifiées. L’automate ne remplit l’identité
« Labo » et ne passe l’avertissement expérimental que dans ces copies réservées.
Constats de l’assistant, sans validation esthétique du créateur :
- Les nappes retenues sont séparées et l’eau reste présente après décoration.
Cela ne suffit pas à rendre les rives naturelles : 42 conserve notamment une
longue retenue sableuse contre le massif ; les liserés restent trop réguliers.
- Les abords des ancres aériennes suivent le sol, sans l’ancien tapis de mousse
surélevé. Le motif alterné terre/herbe et pierre/herbe reste très quadrillé,
particulièrement sur l’ancre automnale de 42 et celle de surface de 2026.
- Certains fonds de bassins de cavité restent herbeux. Leur sédimentation n’est
pas harmonisée avec celle des étangs de surface dans cette itération.
- Les trois massifs diffèrent, mais de grandes bandes et marches rocheuses
persistent, surtout sur 42 et 2026. Les petites entailles n’ont pas suffi à
résoudre cette réserve esthétique. Aucune disparition générale revendiquée.
- Une vue de l’ancre de surface de 42 est masquée par le feuillage ; les autres
points de vue et contrôles de blocs ne remplacent pas sa visite rapprochée.
De larges ombres sont aussi visibles sur 42 : leur cause n’est pas établie.
Pour la prochaine retouche, comparer les mêmes caméras, une modification à la
fois, en commençant par la retenue sur le massif et les chemins quadrillés.
Les trois graines constituent une régression reproductible, pas une preuve
pour toutes les graines ou une validation esthétique de toute la carte.
## Visite manuelle livrée
`build/worldgen-lab/visite193/coherent/42/client/saves/` contient trois copies
neuves : `Sanctuary-Coherent-193-42-Solo`, `Sanctuary-Coherent-193-2026-Solo`
et `Sanctuary-Coherent-193-8675309-Solo`. Elles proviennent des mondes photo
fermés, dont les huit ancres sont inactives et le Bugrock allumé à zéro relais.
Le client manuel est entré sur 42 le 1er octobre 2026 à 01:26:55 Europe/Paris,
vue 32 chunks, simulation 12, joueur spectateur placé devant le massif.
L’automate photo n’est pas activé. Les deux autres mondes sont disponibles
par la liste Solo ; ils n’ont pas été revisités manuellement après leur copie.
Les services d’heure et météo réelle restent désactivés dans ce labo de
comparaison ; midi et temps clair sont préparés dans ces copies seulement.
Quelques avertissements de retard de ticks apparaissent pendant le chargement
à 32 chunks : aucune mesure de fluidité stable n’est revendiquée.
+89
View File
@@ -0,0 +1,89 @@
# WG-FIX-197 — arrivée, cascades et détails du donjon
Branche `codex/worldgen-fixes-beta197`, depuis beta.196. Retours R012 :
arrivée sur l’ISS, cascades souterraines, diagonales de terre dans la mine,
toit de cabane cassé, arrêt chez un ami pendant la création Large sans rapport.
Graine de cet arrêt inconnue. Minecraft 26.3, Fabric 0.19.5, Java 25.
## Changements
Les nouveaux profils `shared_island197_{small,medium,large}` conservent les
densités et biomes du terrain beta.196. Le paramètre additif `polish197`, faux
par défaut, active uniquement les corrections de décoration. Les identifiants
beta.196, données et comportements historiques restent présents. Personnaliser
un profil historique conserve sa révision. Aucune migration ni retouche de
sauvegarde personnelle.
La hauteur du point global ne suffisait pas : `PlayerSpawnFinder` recommence
une recherche depuis la surface la plus haute de chaque colonne. Le toit de
l’ISS pouvait donc être retenu. Sur les nouveaux profils, cette recherche
reste bornée au terrain principal (Y=198–316), avec sol solide, deux blocs
d’air et exclusion des feuilles et troncs. Le rayon aléatoire natif et les
réapparitions personnelles sur un lit restent gérés par Minecraft.
Une poche d’air sous une berge ne suffit plus pour accepter une cascade.
Chaque sortie doit être ouverte au ciel et posséder une face extérieure libre
sur les huit premiers blocs de chute. Les recherches conservent leurs bornes :
dix blocs jusqu’à la sortie, au plus deux bouches de quatre ou cinq blocs.
Une cascade n’est pas forcée si le terrain ne s’y prête pas. Les blocs de chute
ne remplacent jamais un bloc solide réel ; une corniche peut arrêter l’eau.
Le sol des salles minières remplace le modulo 7 par des plaques de terre
cohérentes, dépendantes de la graine. La cabane utilise deux pans d’escaliers
continus, un faîtage, des pignons fermés et des pilotis rejoignant un support.
Son volume est vérifié avant placement et réservé contre les décorations
natives voisines. Aucun grand terrassement ajouté pour imposer une cabane.
## Erreur de création reproduite
La graine **17 en Medium** a ensuite reproduit une exception réelle pendant
la génération du premier chunk : `No supported central gallery floor`, dans
`Cavern183.create`. Aucune cavité admissible n’existait exactement sous (0,0).
Sur beta.197, une recherche locale de roche porteuse sert désormais de repli
pour sculpter la même chambre centrale ; elle ne déplace pas le portail ni les
salles déjà admises sur les autres graines. Création et réouverture de cette
graine réussies en Medium et Large. Ce défaut identifié ne prouve pas encore
la cause de l’arrêt sans rapport chez l’ami. `latest.log` reste utile ; une
ligne indique maintenant taille, graine et plafond mémoire au démarrage.
## Vérifications
- Témoin beta.196 Large, graine 42 : création et réouverture réussies.
- beta.197 : Small 0, Large 42, Medium 17 et Large 17 créés puis rouverts avec
huit ancres, donjon, gemmes, atlas, portail et contrôles d’eau. Les quatre
cabanes ont leurs 99 blocs de toiture intacts, avant et après réouverture.
- Dans ces quatre essais, aucune bouche de cascade extérieure admissible :
les anciennes chutes enfouies sont rejetées. Le contrôle reste conditionnel,
il ne constitue pas une validation visuelle d’une nouvelle cascade acceptée.
- Lecture des blocs sauvegardés des salles Large 42 : ancien motif, 75 blocs
de terre tous isolés ; nouveau sol, 160 blocs dont un seul isolé. La terre
forme donc des plaques au lieu de diagonales pointillées.
- Parcours client natif Vulkan réussi, vue 8 chunks, mémoire Java 2 Gio :
menus FR/EN, trois tailles, Annuler/Échap, aller-retour disque, ancien profil
conservé, types vanilla. Création Large 0 puis arrivée réelle à Y=252 et
huit recherches de spawn aléatoires restées sur l’île. Pas de campagne de
captures, ni de revendication de fluidité à 32 chunks sur le matériel ami.
Les essais Small 0/Large 42 et client ont précédé le dernier repli de galerie,
qui ne s’exécute que lorsqu’aucun des anciens sols n’a été trouvé. Les scénarios
17 vérifient ce changement final. Une première tentative du test client a été
arrêtée pendant l’attente inutile de tous les chunks de la vue ; une fixture
de menu historique a ensuite été corrigée pour conserver la clé publique.
Seul le passage final réussi est retenu.
Traces ignorées : `build/faults197-client-verified.log`,
`build/worldgen-lab/faults197a/{small/0,large/42}/{cold,warm}.json`,
`build/worldgen-lab/faults197b/{medium,large}/17/{cold,warm}.json`.
La panne initiale est conservée dans `faults197a/medium/17/cold.log`.
`./gradlew check build assemblePack assembleTestPack -PsanctuaryFocusedTests=menus`
réussi en 5 min 18 s : contrôles purs, quatre GameTests menus et assemblages.
Export ZIP, versions, dépendances, six presets anciens/nouveaux et toutes les
classes des deux JAR comparés aux classes construites. La dépendance Fabric API
conserve exactement le téléchargement et les hashes vérifiés en beta.196.
Export local `Downloads/Sanctuary-Test-beta.197.mrpack`, **12 276 176 octets**.
SHA-256 : `90b0e0495c7fbdee5ceb1b3c87f177274d89d505a6eea7189358aab3c7fff5b2`.
Guide séparé ; aucun monde, réglage personnel, journal ou secret dans l’archive.
Ni publication du canal ni installation dans Prism. Reçu :
`build/faults197-artifact.json` ; journal général : `build/faults197-check-build.log`.
+79
View File
@@ -0,0 +1,79 @@
# WG-OPTIONS-195 — Sanctuary et les types vanilla
Branche `codex/worldgen-options-beta195`, Minecraft 26.3, depuis beta.194.
## Demande et périmètre
Le créateur reprend la visite de Sanctuary Island pour décider si la génération
peut rester en pause. Il demande une nouvelle île avec la graine 0 et souhaite
examiner le menu principal en quittant le solo. Il précise que la création de
monde doit conserver Sanctuary et les types vanilla, sans les variantes de labo.
Le module Sanctuary Test cesse d'ajouter ses onze anciens presets au tag de
sélection normal. Les types vanilla et `sanctuary:sanctuary` restent disponibles.
Les presets et leurs codecs sont conservés pour les sauvegardes et les lanceurs
de développement ; aucune suppression, migration ou régénération de monde.
Les sélections historiques des GameTests restent dans leurs seules ressources
de test, avec références optionnelles au module Sanctuary Test.
Ce nettoyage ne remplace pas la génération publique Sanctuary par le profil
de laboratoire : leur consolidation reste à décider après la visite. Les options
de taille de Sanctuary sont conservées. Les traductions et identifiants existants
restent identiques ; aucun nouveau libellé d'interface.
## Correction révélée par la graine 0
Le premier démarrage a échoué : `No supported central gallery floor`. La
recherche historique ne sondait que Y=148–212 au centre. En cas d’échec dans le
profil `coherent` seulement, une seconde recherche bornée examine Y=48–240,
avec les mêmes exigences de sol rocheux et de couverture. Les sols déjà admis
sont conservés. Ce correctif concerne le placement de la galerie, pas la forme
de l’île. Le monde avorté est conservé ; le nouvel essai utilise un autre dossier.
## Visite préparée
Nouveau dossier ignoré `build/worldgen-lab/visite195d/coherent/0/`, profil
`sanctuary_test:coherent_landforms_v1`, graine 0, diamètre 724. Le terrain et
les aménagements sont ceux de beta.193, avec le repli de placement décrit
ci-dessus ; beta.194 fournit le menu sans Amis.
Solo spectateur, commandes autorisées, distance de rendu 32, simulation 12,
Vulkan, journée claire pour comparer le terrain. Aucune série de screenshots.
## Vérifications
`./gradlew check build assemblePack assembleTestPack
:sanctuary-test:exportDuoLaunch -PsanctuaryFocusedTests=menus` réussi en 3 min 45 s,
avec les quatre GameTests menus. Après le correctif de galerie, reconstruction
et contrôle du module de laboratoire réussis. Une passe générale supplémentaire
qui avait aussi lancé les tests de capacité est interrompue pour libérer la
machine lors de la visite : elle ne constitue pas un résultat de 265 tests.
Le réassemblage final réussit en 4 s en reprenant les vérifications déjà
réussies, sans les relancer.
Création native de la graine 0 réussie dans `visite195d` : démarrage serveur
14,8 s, contrôle des lieux terminé à 108,1 s, zéro région d’hydrologie lourde.
Trois salles reliées, portail horizontal en (0,131,0), huit ancres avec huit
matériaux distincts, cinq volumes d’eau séparés et 20 033 cellules humides
contrôlées. Les 49 cartes/cadres du palais et les autres contrôles de donjon,
soufre, ruines et gemmes passent. Ces durées incluent des diagnostics et une
construction concurrente ; elles ne sont pas un benchmark de fluidité.
Une copie neuve `Sanctuary-Labo-195-Seed-0` est préparée pour la visite, avec le
visiteur de développement KokaLab déjà inscrit et les ancres dans leur état
initial (le contrôle des offres restaure ses modifications). La graine 0 est
relue dans les données enregistrées. Le client beta.195 a démarré sous Vulkan. Après l’avertissement expérimental,
les journaux confirment KokaLab connecté le 1er octobre à 18:00:35 Europe/Paris,
en (100.5,335,150.5), rendu 32 chunks et simulation 12. Le contrôle natif de
visibilité de la couronne passe. L’examen esthétique et celui du menu principal
sont laissés au créateur.
Journaux : `build/worldgen195-check-build.log`, `build/worldgen195-floor-build.log`,
`build/worldgen195-final-pack.log` (passe interrompue),
`build/worldgen195-assemble.log`, `build/visit195-solo.log` et le rapport natif
`build/worldgen-lab/visite195d/coherent/0/server/worldgen-lab-metrics.json`.
Le reçu `build/worldgen195-artifact.json` confirme que les classes du mod principal
sont identiques à beta.194. Dans le mod de laboratoire, seul `Cavern183.class`
change ; les 22 presets et toutes les ressources du terrain restent identiques,
hormis le tag de sélection. Les anciennes sauvegardes n’ont pas été ouvertes.
Aucune capture ni validation esthétique de cette nouvelle graine revendiquée.
Pas de publication du canal packwiz ni de mise à jour de Prism.
+48
View File
@@ -0,0 +1,48 @@
# Roche jaune — beta.222
## Contrat
Demande du 5 octobre 2026 : renommer « Pierre jaune » en « Roche jaune » et
ajouter les déclinaisons escaliers et dalles, intégrées aux menus Minecraft.
Branche `codex/yellow-rock-variants-beta222`, base `a3dd17c` (beta.221).
Le bloc conserve `sanctuary:yellow_stone`. Les nouveaux identifiants sont
`sanctuary:yellow_stone_stairs` et `sanctuary:yellow_stone_slab`.
Aucun changement de terrain, de profil de génération (221), de format de
sauvegarde ni d'expansion. Aucune modification de monde existant.
## Mise en œuvre
- FR : Roche jaune, Escalier en roche jaune, Dalle en roche jaune.
- EN : Yellow Rock, Yellow Rock Stairs, Yellow Rock Slab.
- Bloc dans Naturel juste après Stone ; famille complète dans Construction
juste après Stone, dans l'ordre bloc, escalier, dalle.
- Texture et teinte du bloc sur les deux variantes, minage à la pioche,
butin d'une variante ou deux dalles pour une dalle double.
- Établi : six blocs donnent quatre escaliers ; trois blocs donnent six dalles.
- Tailleur de pierre : un bloc donne un escalier ou deux dalles.
- Recettes débloquées dans le livre en obtenant de la roche jaune.
## Vérifications du 5 octobre 2026
`./gradlew check build assemblePack :sanctuary-test:exportDuoLaunch
-PsanctuaryFocusedTests=rock222,west221 -PsanctuaryAtlasOnly=true` : réussi,
cinq GameTests passés. Pose et fusion de dalles, coin d’escalier, eau, pioche,
butin simple/double, recettes natives, déblocage du livre et ordre créatif.
Le contrôle du relief 221 reste vert. Une erreur d’import dans le nouveau
GameTest a été corrigée avant ce passage réussi.
Test client ciblé `runClientGameTest` avec `sanctuaryYellowRock222ClientTests`
et backend Vulkan : réussi à 16:49:51. Les 87 états bloc/escalier/dalle ont
la texture stone native, la teinte jaune et le même nombre de faces que leur
équivalent vanilla. Aucun monde ouvert pour ce contrôle de modèles.
Les cinq géométries source, UV et culling sont également comparés aux modèles
Minecraft 26.3. Il ne s’agit pas d’une nouvelle validation visuelle du paysage.
MRpack exporté et vérifié : ZIP intègre, JAR exact, nom FR, modèles teintés,
recettes et trois tailles 221 ; aucun monde ni module de test. Copie dans
`/Users/koka/Downloads/Sanctuary-beta.222.mrpack`.
SHA-256 : `d9ed126f6f6ae2fd425520dae99eafcd91295c2cdde75398f9a2bc929711e005`.
Traces : `build/rock222-build-final.log`, `build/rock222-client.log` et
`build/rock222-mrpack-receipt.json`. Aucun canal public ni instance personnelle
mis à jour. La visite 221 reste ouverte jusqu’au prochain labo Est demandé.
+2 -2
View File
@@ -9,8 +9,8 @@ loom_version=1.17.20
fabric_api_version=0.160.5+26.3
# Release counter: beta.001, .002, .003, ... (see docs/versioning.md).
mod_version=beta.181
pack_version=beta.181
mod_version=beta.235
pack_version=beta.235
resource_pack_version=beta.121
maven_group=fr.koka.sanctuary
jei_version=30.32.0-sanctuary.3
+5 -5
View File
@@ -1,11 +1,11 @@
# Demeure
Mod Fabric autonome pour Minecraft 26.3-pre-2, porté depuis les sources
Service interne à Sanctuary depuis beta.204, pour Minecraft 26.3, porté depuis les sources
historiques référencées par Sanctuary 26.2. Il mesure les empreintes du vivant
et l'attachement aux lieux ; il n'attribue ni propriété ni protection.
Sanctuary l'embarque dans son JAR et utilise son API pour la surcouche de
l'Atlas. Demeure ne dépend pas de Sanctuary. L'hôte peut restreindre les joueurs
Les sources vivent dans `mods/sanctuary/src/main/java/fr/koka/demeure/`.
Sanctuary utilise ce service pour la surcouche de l’Atlas et restreint les joueurs
éligibles avec `DemeureService.setEligibility` ; le pack limite ainsi les
traces aux mondes dont la progression est active et saine.
@@ -27,6 +27,6 @@ une erreur serveur ; le fichier existant est conservé. Les limites sont
explicitées dans [le contrat beta.006](../../docs/demeure-beta006.md).
Les données de l'ancien Demeure ne sont pas importées automatiquement.
`./gradlew :demeure:check :demeure:build` depuis la racine vérifie le modèle
et construit le module. Les tests natifs des événements et de l'Atlas vivent
`./gradlew :sanctuary:demeureSmoke :sanctuary:check` depuis la racine vérifie le modèle
et son intégration. Aucun JAR Demeure séparé ne doit être installé avec beta.204. Les tests natifs des événements et de l'Atlas vivent
dans Sanctuary. Licence GPL-3.0-or-later ; [provenance](PROVENANCE.md).
-27
View File
@@ -1,27 +0,0 @@
plugins { id 'net.fabricmc.fabric-loom' }
group = 'fr.koka.demeure'
version = rootProject.mod_version
base { archivesName = 'demeure' }
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
implementation "net.fabricmc:fabric-loader:${rootProject.loader_version}"
implementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
}
java { toolchain.languageVersion = JavaLanguageVersion.of(25); withSourcesJar() }
tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8'; options.release = 25 }
processResources {
def values = [version: project.version, minecraft: rootProject.minecraft_version.replace('-pre-', '-pre.'), loader: rootProject.loader_version]
inputs.properties(values)
filesMatching('fabric.mod.json') { expand(values) }
}
tasks.named('jar') {
from(rootProject.file('LICENSE')) { rename { 'LICENSE_demeure' } }
from('PROVENANCE.md')
}
tasks.named('test') { failOnNoDiscoveredTests = false }
tasks.register('demeureSmoke', JavaExec) {
dependsOn('testClasses')
classpath = sourceSets.test.runtimeClasspath
mainClass = 'fr.koka.demeure.DemeureSmoke'
}
tasks.named('check') { dependsOn('demeureSmoke') }
@@ -1,13 +0,0 @@
{
"schemaVersion": 1,
"id": "demeure",
"version": "${version}",
"name": "Demeure",
"description": "Living footprints, activity and attachment to places. Sanctuary adaptation.",
"authors": ["KOKA99CAB", "Koka"],
"license": "GPL-3.0-or-later",
"environment": "*",
"entrypoints": {"main": ["fr.koka.demeure.DemeureService"]},
"mixins": ["demeure.mixins.json"],
"depends": {"fabricloader": ">=${loader}", "minecraft": "${minecraft}", "java": ">=25", "fabric-api": "*"}
}
+6
View File
@@ -51,4 +51,10 @@ tasks.register('exportDuoLaunch') {
}
}
tasks.named('test') { failOnNoDiscoveredTests=false }
tasks.register('gallery198Smoke', JavaExec) {
dependsOn('testClasses')
classpath=sourceSets.test.runtimeClasspath
mainClass='fr.koka.sanctuarytest.GalleryFloor198Test'
}
tasks.named('check') { dependsOn('gallery198Smoke') }
tasks.named('jar') { from(rootProject.file('LICENSE')) { rename { 'LICENSE_sanctuary_test' } } }
@@ -12,7 +12,20 @@ final class AdventureChecks180 {
static Map<String,Object> check(ServerLevel level){
var source=(AdventureBiomes180)((NoiseBasedChunkGenerator)level.getChunkSource().getGenerator()).getBiomeSource();
for(var p:Cherry180.sites(source)){level.getChunk(p.getX()>>4,p.getZ()>>4);}
var trees=Cherry180.trees(source);if(trees.size()!=3)throw new IllegalStateException("Expected three main-island cherry trees: "+trees);
var trees=Cherry180.trees(source);
if(trees.isEmpty()){
// On reload the placement counter is empty; inspect the saved trunks without regenerating them.
var saved=new ArrayList<BlockPos>();
int start=source.field().eroded()?0:5,end=source.field().eroded()?15:11;
for(var site:Cherry180.sites(source))for(int x=(site.getX()>>4<<4)+start;x<=(site.getX()>>4<<4)+end;x++)
for(int z=(site.getZ()>>4<<4)+start;z<=(site.getZ()>>4<<4)+end;z++)for(int y=source.field().coherent()?251:271;y<=316;y++){
var p=new BlockPos(x,y,z);
if(level.getBlockState(p).is(Blocks.CHERRY_LOG)&&AdventureCaves180.natural(level.getBlockState(p.below())))saved.add(p);
}
trees=List.copyOf(saved);
}
int expected=source.field().coherent()?Cherry180.sites(source).size():3;
if(expected<2||expected>3||trees.size()!=expected)throw new IllegalStateException("Expected "+expected+" main-island cherry trees: "+trees);
for(var p:trees)if(!level.getBlockState(p).is(Blocks.CHERRY_LOG))throw new IllegalStateException("Missing actual cherry trunk at "+p);
var reefs=source.field().base().reefs();
if(!AdventureCaves180.biome(source,reefs.get(0).x(),reefs.get(0).y(),reefs.get(0).z()).equals("adventure_cherry")||!AdventureCaves180.biome(source,reefs.get(1).x(),reefs.get(1).y(),reefs.get(1).z()).equals("adventure_autumn"))throw new IllegalStateException("Wrong themed reefs");
@@ -0,0 +1,89 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.SanctuaryMod;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ChunkPos;
/** Explicit disposable-lab preparation; never runs in the normal pack or a player's save. */
final class AllIslands231 {
private static final TicketType TICKET=new TicketType(0L,2|8);
private static final int[] CARDINALS={0,2,4,6};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;
int cardinal,index,done;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<ChunkPos> chunks;Map<ChunkPos,CompletableFuture<?>> pending=new LinkedHashMap<>();
}
static void register(){
Registry.register(BuiltInRegistries.TICKET_TYPE,SanctuaryMod.id("lab_all_islands231"),TICKET);
ServerTickEvents.END_SERVER_TICK.register(AllIslands231::tick);
}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started){
require(Boolean.getBoolean("sanctuary.worldgenLab.allIslands"),"Explicit all-islands option required");
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==231&&SharedIsland196.size(level.getChunkSource().getGenerator())==SharedIsland196.Size.LARGE,"Expected new 1024 lab");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;run=r;request(r);
}
private static void request(Run r){
var level=r.server.overworld();int sector=CARDINALS[r.cardinal];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing cardinal anchor");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
var level=server.overworld();var session=ExpansionRuntime.session(level);var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
if(r.chunks==null){
if(!r.request.isDone())return;
var admitted=r.request.join();var island=session.island(admitted.id());
if(!island.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Expansion preparation failed: "+session.progress());return;}
require(r.payment.getCount()==1&&island.diameter()==1024&&island.direction().equals(ExpansionIsland.DIRECTIONS.get(CARDINALS[r.cardinal])),"Wrong cardinal offer");
var relay=adapter.relay(island);require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK),"Missing cardinal relay");
SanctuaryMod.LOGGER.info("ALL_ISLANDS231_ACTIVATED {} {}",island.direction(),relay);
if(++r.cardinal<CARDINALS.length){request(r);return;}
var islands=session.islands();require(islands.size()==9&&islands.stream().allMatch(i->i.status().equals("ready")&&i.diameter()==1024),"Expected nine ready 1024 islands");
var chunks=new LinkedHashSet<ChunkPos>();var manifest=new ArrayList<Map<String,Object>>();
for(var i:islands){
int radius=i.terrainRadius()+ExpansionIsland.DECORATION_MARGIN,count=0;
// Includes the rocky perimeter and decoration margin, not merely the nominal surface.
for(int x=(i.centerX()-radius)>>4;x<=(i.centerX()+radius)>>4;x++)for(int z=(i.centerZ()-radius)>>4;z<=(i.centerZ()+radius)>>4;z++)
if(i.ownsChunk(x,z)){chunks.add(new ChunkPos(x,z));count++;}
var data=new LinkedHashMap<String,Object>();data.put("id",i.id());data.put("direction",i.origin()?"center":i.direction());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("fullChunks",count);
if(!i.origin())data.put("relay",adapter.relay(i).toShortString());manifest.add(data);
}
r.chunks=List.copyOf(chunks);r.result.put("allIslands",manifest);r.result.put("pregenerationTarget",r.chunks.size());
SanctuaryMod.LOGGER.info("ALL_ISLANDS231_PREGEN_BEGIN chunks={}",r.chunks.size());
}
var source=level.getChunkSource();
for(var it=r.pending.entrySet().iterator();it.hasNext();){
var entry=it.next();if(!entry.getValue().isDone())continue;entry.getValue().join();var cp=entry.getKey();
require(source.getChunkNow(cp.x(),cp.z())!=null,"Chunk did not reach FULL: "+cp);
source.removeTicketWithRadius(TICKET,cp,0);it.remove();r.done++;
if(r.done%256==0)SanctuaryMod.LOGGER.info("ALL_ISLANDS231_PREGEN {}/{}",r.done,r.chunks.size());
}
while(r.pending.size()<4&&r.index<r.chunks.size()){
var cp=r.chunks.get(r.index++);r.pending.put(cp,source.addTicketAndLoadWithRadius(TICKET,cp,0));
}
if(r.done==r.chunks.size()){
server.saveEverything(false,true,true);r.result.put("pregeneratedFullChunks",r.done);r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);
run=null;WorldgenDiagnostics.writeReport(r.output,r.result);
}
}catch(Throwable error){
run=null;for(var cp:r.pending.keySet())server.overworld().getChunkSource().removeTicketWithRadius(TICKET,cp,0);
SanctuaryMod.LOGGER.error("ALL_ISLANDS231_FAILED",error);server.halt(false);
}
}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,28 @@
package fr.koka.sanctuarytest;
import java.util.*;
import fr.koka.sanctuary.SanctuaryMod;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.resources.Identifier;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.phys.AABB;
import org.joml.Matrix4f;
/** Verify the actual client frustum hooks once per new lab level, including both terrain APIs. */
final class AscentView184 {
private static final Set<ClientLevel> CHECKED=Collections.newSetFromMap(new WeakHashMap<>());
static void register(){ClientTickEvents.END_CLIENT_TICK.register(client->{
var level=client.level;
if(level==null||!level.dimensionTypeRegistration().is(Identifier.fromNamespaceAndPath("sanctuary_test","ascent_1600"))||!CHECKED.add(level))return;
var frustum=new Frustum(new Matrix4f().scaling(1/4096f),new Matrix4f());
var crown=new AABB(-32,1152,-32,32,1328,32);var root=new AABB(-16,624,-16,16,672,16);
var cube=new BoundingBox(-32,1152,-32,32,1328,32);
frustum.prepare(0,250,0);
if(frustum.isVisible(crown)||frustum.cubeInFrustum(cube)<0||!frustum.isVisible(root))throw new IllegalStateException("Ascent ground reveal regression");
frustum.prepare(0,640,0);
if(!frustum.isVisible(crown)||frustum.cubeInFrustum(cube)>=0)throw new IllegalStateException("Ascent crown remains hidden at rosette");
SanctuaryMod.LOGGER.info("ASCENT_VIEW_VERIFIED groundHidden=true rosetteVisible=true crownRevealedAt640=true");
});}
}
@@ -0,0 +1,98 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Four real offers, interruption/reload, local generation and shoreline planting on fresh lab worlds. */
final class Diagonal225Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal225Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==225,"Wrong profile");result.put("verificationScope","diagonal225");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain225.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain225.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain225.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain225.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=190;y<304;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
}
habitatCounts.put(entry.getKey(),plants);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
if(i.direction().endsWith("east")){
require(wetSample!=null,"No wet depression");level.getChunkAt(wetSample);
require(level.getFluidState(wetSample).is(net.minecraft.tags.FluidTags.WATER),"Dry wetland at "+wetSample);
// A mangrove biome includes dry banks too. Check the actual depression, not just its first habitat sample.
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL225_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL225_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,114 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Four real offers, interruption/reload, local generation and shoreline planting on fresh lab worlds. */
final class Diagonal226Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal226Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==226,"Wrong profile");result.put("verificationScope","diagonal226");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain226.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain226.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50&&c.top()>0)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain226.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain226.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<480;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
}
habitatCounts.put(entry.getKey(),plants);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
if(i.direction().equals("northeast")){
require(wetSample!=null,"No wet depression");level.getChunkAt(wetSample);
require(level.getFluidState(wetSample).is(net.minecraft.tags.FluidTags.WATER),"Dry wetland at "+wetSample);
// A mangrove biome includes dry banks too. Check the actual depression, not just its first habitat sample.
}
int floodedTrees=0;
if(i.direction().equals("northeast")){
var visited=new HashSet<ChunkPos>();
search:for(int dx=-420;dx<=420;dx+=24)for(int dz=-420;dz<=420;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(!c.water()||c.top()<DiagonalTerrain226.WATER-2)continue;
var cp=new ChunkPos(x>>4,z>>4);if(!visited.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++){
var before=f.column(xx,zz);if(!before.water())continue;
var root=new BlockPos(xx,before.top()+1,zz);
if(chunk.getBlockState(root).is(net.minecraft.tags.BlockTags.LOGS))floodedTrees++;
}
if(floodedTrees>=3||visited.size()>=24)break search;
}
require(floodedTrees>0,"No native tree rooted inside the shallow marsh");
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("floodedTrees",floodedTrees);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL226_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL226_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,152 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Four real offers, interruption/reload, local generation and shoreline planting on fresh lab worlds. */
final class Diagonal227Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal227Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==227,"Wrong profile");result.put("verificationScope","diagonal227");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain227.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain227.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50&&c.top()>0)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain227.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain227.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<480;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
}
habitatCounts.put(entry.getKey(),plants);
}
// A savanna is sparse: one random chunk per habitat is not a forest census.
// If the first samples are treeless, inspect additional supported savanna chunks.
if(i.direction().equals("southwest")&&(logs==0||leaves==0)){
var checked=new HashSet<ChunkPos>(samples.values());int extra=0;
search:for(int dx=-360;dx<=360;dx+=24)for(int dz=-360;dz<=360;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(c.top()<120||!c.biome().startsWith("savanna"))continue;
var cp=new ChunkPos(x>>4,z>>4);if(!checked.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=80;y<280;y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(net.minecraft.tags.BlockTags.LOGS))logs++;if(state.is(net.minecraft.tags.BlockTags.LEAVES))leaves++;
}
extra++;if(logs>0&&leaves>0||extra>=18)break search;
}
habitatCounts.put("additionalSavannaChunks",extra);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
if(i.direction().equals("northeast")){
require(wetSample!=null,"No wet depression");level.getChunkAt(wetSample);
require(level.getFluidState(wetSample).is(net.minecraft.tags.FluidTags.WATER),"Dry wetland at "+wetSample);
// A mangrove biome includes dry banks too. Check the actual depression, not just its first habitat sample.
}
int floodedTrees=0;
if(i.direction().equals("northeast")){
var visited=new HashSet<ChunkPos>();
search:for(int dx=-420;dx<=420;dx+=24)for(int dz=-420;dz<=420;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(!c.water()||c.top()<DiagonalTerrain227.WATER-2)continue;
var cp=new ChunkPos(x>>4,z>>4);if(!visited.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++){
var before=f.column(xx,zz);if(!before.water())continue;
var root=new BlockPos(xx,before.top()+1,zz);
if(chunk.getBlockState(root).is(net.minecraft.tags.BlockTags.LOGS))floodedTrees++;
}
if(floodedTrees>=3||visited.size()>=24)break search;
}
require(floodedTrees>0,"No native tree rooted inside the shallow marsh");
}
var caveCounts=new TreeMap<String,Integer>();
if(i.direction().equals("southeast")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<150)continue;
for(int y=Math.max(48,c.bottom()+8);y<Math.min(312,c.top()-32);y+=12){
var biome=f.biome(x,y,z);if(!biome.endsWith("227")||f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of("sanctuary:diagonal_lush227","sanctuary:diagonal_dripstone227")){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<Math.min(320,f.top(x,z)-28);y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(biome.endsWith("lush227")?(state.is(Blocks.MOSS_BLOCK)||state.is(Blocks.CAVE_VINES)||state.is(Blocks.CAVE_VINES_PLANT)||state.is(Blocks.SPORE_BLOSSOM)):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>20||++checked>=16)break;
}
require(blocks>20,"Missing native cave vegetation "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("floodedTrees",floodedTrees);data.put("caveBlocks",caveCounts);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL227_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL227_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,152 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Four real offers, interruption/reload, local generation and shoreline planting on fresh lab worlds. */
final class Diagonal228Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal228Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==228,"Wrong profile");result.put("verificationScope","diagonal228");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain228.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain228.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50&&c.top()>0)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain228.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain228.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<480;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
}
habitatCounts.put(entry.getKey(),plants);
}
// A savanna is sparse: one random chunk per habitat is not a forest census.
// If the first samples are treeless, inspect additional supported savanna chunks.
if(i.direction().equals("southwest")&&(logs==0||leaves==0)){
var checked=new HashSet<ChunkPos>(samples.values());int extra=0;
search:for(int dx=-360;dx<=360;dx+=24)for(int dz=-360;dz<=360;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(c.top()<120||!c.biome().startsWith("savanna"))continue;
var cp=new ChunkPos(x>>4,z>>4);if(!checked.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=80;y<280;y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(net.minecraft.tags.BlockTags.LOGS))logs++;if(state.is(net.minecraft.tags.BlockTags.LEAVES))leaves++;
}
extra++;if(logs>0&&leaves>0||extra>=18)break search;
}
habitatCounts.put("additionalSavannaChunks",extra);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
if(i.direction().equals("northeast")){
require(wetSample!=null,"No wet depression");level.getChunkAt(wetSample);
require(level.getFluidState(wetSample).is(net.minecraft.tags.FluidTags.WATER),"Dry wetland at "+wetSample);
// A mangrove biome includes dry banks too. Check the actual depression, not just its first habitat sample.
}
int floodedTrees=0;
if(i.direction().equals("northeast")){
var visited=new HashSet<ChunkPos>();
search:for(int dx=-420;dx<=420;dx+=24)for(int dz=-420;dz<=420;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(!c.water()||c.top()<DiagonalTerrain228.WATER-2)continue;
var cp=new ChunkPos(x>>4,z>>4);if(!visited.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++){
var before=f.column(xx,zz);if(!before.water())continue;
var root=new BlockPos(xx,before.top()+1,zz);
if(chunk.getBlockState(root).is(net.minecraft.tags.BlockTags.LOGS))floodedTrees++;
}
if(floodedTrees>=3||visited.size()>=24)break search;
}
require(floodedTrees>0,"No native tree rooted inside the shallow marsh");
}
var caveCounts=new TreeMap<String,Integer>();
if(i.direction().equals("southeast")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<150)continue;
for(int y=Math.max(48,c.bottom()+8);y<Math.min(312,c.top()-32);y+=12){
var biome=f.biome(x,y,z);if(!biome.endsWith("227")||f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of("sanctuary:diagonal_lush227","sanctuary:diagonal_dripstone227")){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<Math.min(320,f.top(x,z)-28);y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(biome.endsWith("lush227")?(state.is(Blocks.MOSS_BLOCK)||state.is(Blocks.CAVE_VINES)||state.is(Blocks.CAVE_VINES_PLANT)||state.is(Blocks.SPORE_BLOSSOM)):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>20||++checked>=16)break;
}
require(blocks>20,"Missing native cave vegetation "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("floodedTrees",floodedTrees);data.put("caveBlocks",caveCounts);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL228_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL228_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,174 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Real offers and reload with native lower pale trees, upper fireflies and dry cave features. */
final class Diagonal229Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal229Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==229,"Wrong profile");result.put("verificationScope","diagonal229");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain229.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain229.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50&&c.top()>0)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain229.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain229.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<480;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
}
habitatCounts.put(entry.getKey(),plants);
}
// A savanna is sparse: one random chunk per habitat is not a forest census.
// If the first samples are treeless, inspect additional supported savanna chunks.
if(i.direction().equals("southwest")&&(logs==0||leaves==0)){
var checked=new HashSet<ChunkPos>(samples.values());int extra=0;
search:for(int dx=-360;dx<=360;dx+=24)for(int dz=-360;dz<=360;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(c.top()<120||!c.biome().startsWith("savanna"))continue;
var cp=new ChunkPos(x>>4,z>>4);if(!checked.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=80;y<280;y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(net.minecraft.tags.BlockTags.LOGS))logs++;if(state.is(net.minecraft.tags.BlockTags.LEAVES))leaves++;
}
extra++;if(logs>0&&leaves>0||extra>=18)break search;
}
habitatCounts.put("additionalSavannaChunks",extra);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
int paleLogs=0,fireflies=0,paleChunks=0;
if(i.direction().equals("northeast")){
var visited=new HashSet<ChunkPos>();
search:for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){
var cp=new ChunkPos((i.centerX()+dx)>>4,(i.centerZ()+dz)>>4);
if(DiagonalVegetation229.paleSites(f,cp).isEmpty()||!visited.add(cp))continue;
var chunk=level.getChunk(cp.x(),cp.z());paleChunks++;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<448;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(Blocks.PALE_OAK_LOG)){require(y<f.top(x,z),"Pale oak outside lower habitat");paleLogs++;}
if(state.is(Blocks.FIREFLY_BUSH)){require(y==f.top(x,z)+1,"Firefly bush in lower pale habitat");fireflies++;}
if(state.is(Blocks.WATER)){
var at=p.immutable();require(f.pool(cp).contains(at),"Unplanned water in the wetland at "+at);
require(chunk.getBlockState(at.below()).isSolidRender(),"Water without natural floor");
for(var dir:Direction.Plane.HORIZONTAL){var side=at.relative(dir);require(f.pool(cp).contains(side)||chunk.getBlockState(side).isSolidRender(),"Leaking natural pool");}
}
}
if(paleLogs>20&&fireflies>0||paleChunks>=24)break search;
}
require(paleLogs>0&&fireflies>0,"Missing pale trees or upper fireflies: "+paleLogs+"/"+fireflies+" chunks="+paleChunks);
}
var caveCounts=new TreeMap<String,Integer>();
if(i.direction().equals("southeast")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<150)continue;
for(int y=Math.max(48,c.bottom()+8);y<Math.min(312,c.top()-32);y+=12){
var biome=f.biome(x,y,z);if(!biome.endsWith("227")||f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of("sanctuary:diagonal_lush227","sanctuary:diagonal_dripstone227")){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<Math.min(320,f.top(x,z)-28);y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(biome.endsWith("lush227")?(state.is(Blocks.MOSS_BLOCK)||state.is(Blocks.CAVE_VINES)||state.is(Blocks.CAVE_VINES_PLANT)||state.is(Blocks.SPORE_BLOSSOM)):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>20||++checked>=16)break;
}
require(blocks>20,"Missing native cave vegetation "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
if(i.direction().equals("southwest")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
for(int y=Math.max(40,c.bottom());y<c.top()-12;y+=8){
String biome=f.biome(x,y,z);if(f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of(DiagonalTerrain229.SULFUR,DiagonalTerrain229.DRIP)){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<f.top(x,z)-12;y++){
var state=chunk.getBlockState(p.set(x,y,z));
require(!state.is(Blocks.MOSS_BLOCK)&&!state.is(Blocks.CAVE_VINES)&&!state.is(Blocks.SPORE_BLOSSOM),"Lush decoration in southwest");
if(biome.equals(DiagonalTerrain229.SULFUR)?state.is(Blocks.SULFUR_SPIKE):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>5||++checked>=24)break;
}
require(blocks>0,"Missing native dry cave decoration "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("paleLogs",paleLogs);data.put("upperFireflies",fireflies);data.put("paleChunks",paleChunks);data.put("caveBlocks",caveCounts);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL229_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL229_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,194 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Real offers and reload with native lower pale trees, upper fireflies and dry cave features. */
final class Diagonal230Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal230Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==230,"Wrong profile");result.put("verificationScope","diagonal230");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain230.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain230.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
int paleLogs=0,fireflies=0,paleChunks=0,openPaleRoots=0,neDrip=0,yellowRock=0,greyStone=0;
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50&&c.top()>0)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain230.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain230.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<480;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
if(i.direction().equals("northeast")&&state.is(Blocks.FIREFLY_BUSH)){
require(y==f.top(x,z)+1&&!f.lower(x,y,z),"Firefly bush in lower habitat");fireflies++;
}
}
habitatCounts.put(entry.getKey(),plants);
}
// A savanna is sparse: one random chunk per habitat is not a forest census.
// If the first samples are treeless, inspect additional supported savanna chunks.
if(i.direction().equals("southwest")&&(logs==0||leaves==0)){
var checked=new HashSet<ChunkPos>(samples.values());int extra=0;
search:for(int dx=-360;dx<=360;dx+=24)for(int dz=-360;dz<=360;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(c.top()<120||!c.biome().startsWith("savanna"))continue;
var cp=new ChunkPos(x>>4,z>>4);if(!checked.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=80;y<280;y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(net.minecraft.tags.BlockTags.LOGS))logs++;if(state.is(net.minecraft.tags.BlockTags.LEAVES))leaves++;
}
extra++;if(logs>0&&leaves>0||extra>=18)break search;
}
habitatCounts.put("additionalSavannaChunks",extra);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
if(i.direction().equals("northeast")){
var visited=new HashSet<ChunkPos>();
search:for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){
var cp=new ChunkPos((i.centerX()+dx)>>4,(i.centerZ()+dz)>>4);
if(DiagonalVegetation230.paleSites(f,cp).isEmpty()||!visited.add(cp))continue;
var chunk=level.getChunk(cp.x(),cp.z());paleChunks++;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<448;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(Blocks.PALE_OAK_LOG)){
paleLogs++;if(chunk.getBlockState(p.below()).is(Blocks.DIRT)){require(f.lower(x,y,z),"Pale oak rooted on upper plateau");if(y==f.top(x,z)+1)openPaleRoots++;}
}
if(state.is(Blocks.POINTED_DRIPSTONE))neDrip++;
if(state.is(Blocks.FIREFLY_BUSH)){require(y==f.top(x,z)+1&&!f.lower(x,y,z),"Firefly bush in lower pale habitat");fireflies++;}
if(state.is(Blocks.WATER)){
var at=p.immutable();require(f.pool(cp).contains(at),"Unplanned water in the wetland at "+at);
require(chunk.getBlockState(at.below()).isSolidRender(),"Water without natural floor");
for(var dir:Direction.Plane.HORIZONTAL){var side=at.relative(dir);require(f.pool(cp).contains(side)||chunk.getBlockState(side).isSolidRender(),"Leaking natural pool");}
}
}
if(paleLogs>20&&openPaleRoots>0&&neDrip>0&&fireflies>0||paleChunks>=32)break search;
}
require(paleLogs>0&&openPaleRoots>0&&neDrip>0&&fireflies>0,"Missing lower open trees/dripstone/upper fireflies: "+paleLogs+"/"+openPaleRoots+"/"+neDrip+"/"+fireflies+" chunks="+paleChunks);
}
var caveCounts=new TreeMap<String,Integer>();
if(i.direction().equals("southeast")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<150)continue;
for(int y=Math.max(48,c.bottom()+8);y<Math.min(312,c.top()-32);y+=12){
var biome=f.biome(x,y,z);if(!biome.endsWith("227")||f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of("sanctuary:diagonal_lush227","sanctuary:diagonal_dripstone227")){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<Math.min(320,f.top(x,z)-28);y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(biome.endsWith("lush227")?(state.is(Blocks.MOSS_BLOCK)||state.is(Blocks.CAVE_VINES)||state.is(Blocks.CAVE_VINES_PLANT)||state.is(Blocks.SPORE_BLOSSOM)):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>20||++checked>=16)break;
}
require(blocks>20,"Missing native cave vegetation "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
if(i.direction().equals("southwest")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
for(int y=Math.max(40,c.bottom());y<c.top()-12;y+=8){
String biome=f.biome(x,y,z);if(f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of(DiagonalTerrain230.SULFUR,DiagonalTerrain230.DRIP)){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<f.top(x,z)-12;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(fr.koka.sanctuary.building.YellowStone.BLOCK))yellowRock++;if(state.is(Blocks.STONE))greyStone++;
require(!state.is(Blocks.MOSS_BLOCK)&&!state.is(Blocks.CAVE_VINES)&&!state.is(Blocks.SPORE_BLOSSOM),"Lush decoration in southwest");
if(biome.equals(DiagonalTerrain230.SULFUR)?state.is(Blocks.SULFUR_SPIKE):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>5||++checked>=24)break;
}
require(blocks>0,"Missing native dry cave decoration "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
if(i.direction().equals("southwest")){
int extra=0;
search:for(int dx=-360;dx<=360;dx+=48)for(int dz=-360;dz<=360;dz+=48){
if(yellowRock>100&&greyStone>100)break search;
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<140||!f.state(x,c.top()-8,z).is(Blocks.STONE))continue;
var cp=new ChunkPos(x>>4,z>>4);var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=40;y<f.top(xx,zz);y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(fr.koka.sanctuary.building.YellowStone.BLOCK))yellowRock++;if(state.is(Blocks.STONE))greyStone++;
}
if(++extra>=12)break search;
}
require(yellowRock>100&&greyStone>100,"Missing mixed savanna geology");
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("paleLogs",paleLogs);data.put("openPaleRoots",openPaleRoots);data.put("neDripstone",neDrip);data.put("yellowRock",yellowRock);data.put("greyStone",greyStone);data.put("upperFireflies",fireflies);data.put("paleChunks",paleChunks);data.put("caveBlocks",caveCounts);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL230_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL230_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,200 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.ChunkPos;
/** Real offers and reload with native lower pale trees, upper fireflies and dry cave features. */
final class Diagonal231Checks {
private static final int[] SECTORS={1,3,5,7};
private static Run run;
private static final class Run {
MinecraftServer server;Path output;Map<String,Object> result;long started;boolean fresh;
int index;CompletableFuture<ExpansionIsland> request;ItemStack payment;
List<Map<String,Object>> islands=new ArrayList<>();
}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Diagonal231Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==231,"Wrong profile");result.put("verificationScope","diagonal231");
var r=new Run();r.server=server;r.output=output;r.result=result;r.started=started;r.fresh=fresh;
if(fresh)request(r);else{
var saved=ExpansionRuntime.session(level).islands();require(saved.size()==2,"Reservation lost");
r.request=CompletableFuture.completedFuture(saved.get(1));r.payment=ItemStack.EMPTY;
}
run=r;
}
private static void request(Run r){
var level=r.server.overworld();int sector=SECTORS[r.index];
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var bad=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,bad,()->true).isCompletedExceptionally()&&bad.getCount()==64,"Wrong payment accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);r.payment=new ItemStack(demand.item(),demand.count()+1);
r.request=RelayOffers199.offer(level,pos,r.payment,()->true);
require(RelayOffers199.offer(level,pos,r.payment,()->true).isCompletedExceptionally(),"Duplicate offer accepted");
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server!=server)return;
try{
require(System.nanoTime()-r.started<java.util.concurrent.TimeUnit.MINUTES.toNanos(12),"Timeout");if(!r.request.isDone())return;
var admitted=r.request.join();var level=server.overworld();var session=ExpansionRuntime.session(level);var a=LabExpansions199.get(level.getChunkSource().getGenerator());
require(DiagonalTerrain231.active(admitted)&&ExpansionIsland.DIRECTIONS.indexOf(admitted.direction())==SECTORS[r.index],"Wrong diagonal/size");
require(admitted.climate().equals(DiagonalTerrain225.climate(admitted.direction())),"Wrong humidity axis");
if(r.fresh){
require(r.payment.getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");
r.result.put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
require(a.preparationChunks(i).size()==49,"Unbounded preparation");var f=DiagonalTerrain231.field(i);var relay=a.relay(i);
require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==SECTORS[r.index],"Missing/wrong relay");
try{RelayOffers199.offer(level,relay,new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Unusable relay");}
if(r.index>0)require(r.payment.getCount()==1,"Incorrect offer cost");
int grass=0,flowers=0,carpets=0,hanging=0;
int paleLogs=0,fireflies=0,paleChunks=0,openPaleRoots=0,neDrip=0,yellowRock=0,greyStone=0;
var samples=new TreeMap<String,ChunkPos>();BlockPos wetSample=null;
for(int dx=-400;dx<=400;dx+=24)for(int dz=-400;dz<=400;dz+=24){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()>50&&c.top()>0)samples.putIfAbsent(c.biome(),new ChunkPos(x>>4,z>>4));if(wetSample==null&&c.water()&&c.top()<DiagonalTerrain230.WATER-2)wetSample=new BlockPos(x,DiagonalTerrain230.WATER,z);}
int logs=0,leaves=0,water=0,cactus=0;var p=new BlockPos.MutableBlockPos();var habitatCounts=new TreeMap<String,Integer>();
for(var entry:samples.entrySet()){
var cp=entry.getValue();var chunk=level.getChunk(cp.x(),cp.z());int plants=0;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<480;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(net.minecraft.tags.BlockTags.LOGS)){logs++;plants++;}
if(state.is(net.minecraft.tags.BlockTags.LEAVES)){leaves++;plants++;}
if(state.is(Blocks.CACTUS)){cactus++;plants++;}
if(state.is(Blocks.WATER))water++;
if(i.direction().equals("northeast")&&state.is(Blocks.FIREFLY_BUSH)){
require(y==f.top(x,z)+1&&!f.lower(x,y,z),"Firefly bush in lower habitat");fireflies++;
}
}
habitatCounts.put(entry.getKey(),plants);
}
// A savanna is sparse: one random chunk per habitat is not a forest census.
// If the first samples are treeless, inspect additional supported savanna chunks.
if(i.direction().equals("southwest")&&(logs==0||leaves==0)){
var checked=new HashSet<ChunkPos>(samples.values());int extra=0;
search:for(int dx=-360;dx<=360;dx+=24)for(int dz=-360;dz<=360;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
if(c.top()<120||!c.biome().startsWith("savanna"))continue;
var cp=new ChunkPos(x>>4,z>>4);if(!checked.add(cp))continue;var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=80;y<280;y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(net.minecraft.tags.BlockTags.LOGS))logs++;if(state.is(net.minecraft.tags.BlockTags.LEAVES))leaves++;
}
extra++;if(logs>0&&leaves>0||extra>=18)break search;
}
habitatCounts.put("additionalSavannaChunks",extra);
}
require(logs>0&&leaves>0,"No native forest on "+i.direction()+" "+habitatCounts);
if(i.direction().equals("northeast")){
var visited=new HashSet<ChunkPos>();
search:for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){
var cp=new ChunkPos((i.centerX()+dx)>>4,(i.centerZ()+dz)>>4);
if(DiagonalVegetation230.paleSites(f,cp).isEmpty()||!visited.add(cp))continue;
var chunk=level.getChunk(cp.x(),cp.z());paleChunks++;
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=32;y<448;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(Blocks.PALE_OAK_LOG)){
paleLogs++;if(chunk.getBlockState(p.below()).is(Blocks.DIRT)){require(f.lower(x,y,z),"Pale oak rooted on upper plateau");if(y==f.top(x,z)+1)openPaleRoots++;}
}
if(state.is(Blocks.POINTED_DRIPSTONE))neDrip++;
if(state.is(Blocks.SHORT_GRASS)||state.is(Blocks.TALL_GRASS))grass++;
if(state.is(Blocks.CLOSED_EYEBLOSSOM)||state.is(Blocks.OPEN_EYEBLOSSOM))flowers++;
if(state.is(Blocks.PALE_MOSS_CARPET))carpets++;
if(state.is(Blocks.PALE_HANGING_MOSS))hanging++;
if(state.is(Blocks.FIREFLY_BUSH)){require(y==f.top(x,z)+1&&!f.lower(x,y,z),"Firefly bush in lower pale habitat");fireflies++;}
if(state.is(Blocks.WATER)){
var at=p.immutable();require(f.pool(cp).contains(at),"Unplanned water in the wetland at "+at);
require(chunk.getBlockState(at.below()).isSolidRender(),"Water without natural floor");
for(var dir:Direction.Plane.HORIZONTAL){var side=at.relative(dir);require(f.pool(cp).contains(side)||chunk.getBlockState(side).isSolidRender(),"Leaking natural pool");}
}
}
if(paleLogs>20&&openPaleRoots>0&&neDrip>0&&fireflies>0&&grass>0&&flowers>0&&carpets>0||paleChunks>=32)break search;
}
require(grass>0&&flowers>0&&carpets>0,"Missing understory: "+grass+"/"+flowers+"/"+carpets);
require(paleLogs>0&&openPaleRoots>0&&neDrip>0&&fireflies>0,"Missing lower open trees/dripstone/upper fireflies: "+paleLogs+"/"+openPaleRoots+"/"+neDrip+"/"+fireflies+" chunks="+paleChunks);
}
var caveCounts=new TreeMap<String,Integer>();
if(i.direction().equals("southeast")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<150)continue;
for(int y=Math.max(48,c.bottom()+8);y<Math.min(312,c.top()-32);y+=12){
var biome=f.biome(x,y,z);if(!biome.endsWith("227")||f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of("sanctuary:diagonal_lush227","sanctuary:diagonal_dripstone227")){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<Math.min(320,f.top(x,z)-28);y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(biome.endsWith("lush227")?(state.is(Blocks.MOSS_BLOCK)||state.is(Blocks.CAVE_VINES)||state.is(Blocks.CAVE_VINES_PLANT)||state.is(Blocks.SPORE_BLOSSOM)):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>20||++checked>=16)break;
}
require(blocks>20,"Missing native cave vegetation "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
if(i.direction().equals("southwest")){
var candidates=new TreeMap<String,LinkedHashSet<ChunkPos>>();
for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);
for(int y=Math.max(40,c.bottom());y<c.top()-12;y+=8){
String biome=f.biome(x,y,z);if(f.density(x,y,z)>0)continue;
candidates.computeIfAbsent(biome,k->new LinkedHashSet<>()).add(new ChunkPos(x>>4,z>>4));break;
}
}
for(String biome:List.of(DiagonalTerrain230.SULFUR,DiagonalTerrain230.DRIP)){
int blocks=0,checked=0;
for(var cp:candidates.getOrDefault(biome,new LinkedHashSet<>())){
var chunk=level.getChunk(cp.x(),cp.z());
for(int x=cp.getMinBlockX();x<=cp.getMaxBlockX();x++)for(int z=cp.getMinBlockZ();z<=cp.getMaxBlockZ();z++)for(int y=40;y<f.top(x,z)-12;y++){
var state=chunk.getBlockState(p.set(x,y,z));
if(state.is(fr.koka.sanctuary.building.YellowStone.BLOCK))yellowRock++;if(state.is(Blocks.STONE))greyStone++;
require(!state.is(Blocks.MOSS_BLOCK)&&!state.is(Blocks.CAVE_VINES)&&!state.is(Blocks.SPORE_BLOSSOM),"Lush decoration in southwest");
if(biome.equals(DiagonalTerrain230.SULFUR)?state.is(Blocks.SULFUR_SPIKE):state.is(Blocks.POINTED_DRIPSTONE))blocks++;
}
if(blocks>5||++checked>=24)break;
}
require(blocks>0,"Missing native dry cave decoration "+biome+" chunks="+checked);caveCounts.put(biome,blocks);
}
}
if(i.direction().equals("southwest")){
int extra=0;
search:for(int dx=-360;dx<=360;dx+=48)for(int dz=-360;dz<=360;dz+=48){
if(yellowRock>100&&greyStone>100)break search;
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.top()<140||!f.state(x,c.top()-8,z).is(Blocks.STONE))continue;
var cp=new ChunkPos(x>>4,z>>4);var chunk=level.getChunk(cp.x(),cp.z());
for(int xx=cp.getMinBlockX();xx<=cp.getMaxBlockX();xx++)for(int zz=cp.getMinBlockZ();zz<=cp.getMaxBlockZ();zz++)for(int y=40;y<f.top(xx,zz);y++){
var state=chunk.getBlockState(p.set(xx,y,zz));if(state.is(fr.koka.sanctuary.building.YellowStone.BLOCK))yellowRock++;if(state.is(Blocks.STONE))greyStone++;
}
if(++extra>=12)break search;
}
require(yellowRock>100&&greyStone>100,"Missing mixed savanna geology");
}
var data=new LinkedHashMap<String,Object>();data.put("direction",i.direction());data.put("id",i.id());data.put("diameter",i.diameter());data.put("x",i.centerX());data.put("z",i.centerZ());data.put("seed",i.seed());data.put("relay",relay.toShortString());data.put("biomes",habitatCounts);data.put("logs",logs);data.put("leaves",leaves);data.put("water",water);if(wetSample!=null)data.put("waterProbe",wetSample.toShortString());data.put("cactus",cactus);data.put("paleLogs",paleLogs);data.put("grass",grass);data.put("flowers",flowers);data.put("carpets",carpets);data.put("hangingMoss",hanging);data.put("openPaleRoots",openPaleRoots);data.put("neDripstone",neDrip);data.put("yellowRock",yellowRock);data.put("greyStone",greyStone);data.put("upperFireflies",fireflies);data.put("paleChunks",paleChunks);data.put("caveBlocks",caveCounts);data.put("preparedChunks",a.preparationChunks(i).size());r.islands.add(data);
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("DIAGONAL231_CHECKED {}",data);
if(++r.index<4){request(r);return;}
var source=Anchors189.source(level.getChunkSource().getGenerator());int cane=0;
for(var entry:SugarCane225.banks(source).entrySet()){
level.getChunk(entry.getKey().x(),entry.getKey().z());
for(var pos:entry.getValue())if(level.getBlockState(pos).is(Blocks.SUGAR_CANE)){
require(level.getBlockState(pos).canSurvive(level,pos),"Cane without water");cane++;
}
}
require(cane>5,"Missing island sugar cane: "+cane);r.result.put("sugarCaneColumns",cane);r.result.put("islands",r.islands);if(Boolean.getBoolean("sanctuary.worldgenLab.allIslands")){run=null;AllIslands231.begin(r.server,r.output,r.result,r.started);return;}finish(r);
}catch(Throwable error){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("DIAGONAL231_CHECK_FAILED",error);server.halt(false);}
}
private static void finish(Run r){run=null;r.result.put("readyForVisitMs",(System.nanoTime()-r.started)/1_000_000);WorldgenDiagnostics.writeReport(r.output,r.result);}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,99 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.*;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
/** Actual East anchor transaction/restart, native jungle temple, sealed lava and native vegetation. */
final class East223Checks {
private record Run(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh,CompletableFuture<ExpansionIsland> request,ItemStack payment) {}
private static Run run;
static void register(){ServerTickEvents.END_SERVER_TICK.register(East223Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&(adapter.rootGeneration()==223||adapter.rootGeneration()==224),"Wrong profile");var session=ExpansionRuntime.session(level);result.put("verificationScope","east"+adapter.rootGeneration());
if(fresh){
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==2).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing East anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var wrong=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,wrong,()->true).isCompletedExceptionally()&&wrong.getCount()==64,"Wrong offer accepted");
var demand=AnchorOffers189.DEMANDS.get(2);var payment=new ItemStack(demand.item(),demand.count()+1);var request=RelayOffers199.offer(level,pos,payment,()->true);
require(RelayOffers199.offer(level,pos,payment,()->true).isCompletedExceptionally(),"Duplicate accepted");result.put("anchor",pos.toShortString());
run=new Run(server,output,result,started,true,request,payment);
}else{
require(session.islands().size()==2,"Reservation not restored");run=new Run(server,output,result,started,false,CompletableFuture.completedFuture(session.islands().get(1)),ItemStack.EMPTY);
}
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server()!=server)return;
try{
require(System.nanoTime()-r.started()<java.util.concurrent.TimeUnit.MINUTES.toNanos(8),"Timeout");if(!r.request().isDone())return;
var admitted=r.request().join();var level=server.overworld();var session=ExpansionRuntime.session(level);
require(EastVolcano223.active(admitted)&&admitted.centerX()>0&&Math.abs(admitted.centerZ())/Math.abs((double)admitted.centerX())<.28,"Wrong East placement");
r.result().put("expansion",Map.of("id",admitted.id(),"x",admitted.centerX(),"z",admitted.centerZ(),"diameter",admitted.diameter(),"seed",admitted.seed()));
if(r.fresh()){require(r.payment().getCount()==1&&session.island(admitted.id()).status().equals("reserved"),"Payment/interruption failed");r.result().put("interruptedProgress",session.progress());finish(r);return;}
var i=session.island(admitted.id());if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
var a=LabExpansions199.get(level.getChunkSource().getGenerator());var relay=RegionalRelay215.plan(i);var f=EastVolcano223.field(i);var temple=EastTemple223.plan(i);
require(a.preparationChunks(i).size()<=100,"Unbounded preparation");int relayBlocks=0;
for(var part:relay.chunks().values())for(var entry:part.entrySet()){require(level.getBlockState(entry.getKey())==entry.getValue(),"Relay mismatch "+entry.getKey());relayBlocks++;}
try{RelayOffers199.offer(level,relay.anchor(),new ItemStack(Items.DIRT),()->true).join();throw new AssertionError("Bad relay payment");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Relay unrecognized");}
int chests=0,traps=0,masonry=0;var pos=new BlockPos.MutableBlockPos();var bounds=temple.bounds();
for(int x=bounds.minX();x<=bounds.maxX();x++)for(int z=bounds.minZ();z<=bounds.maxZ();z++)for(int y=bounds.minY();y<=bounds.maxY();y++){
var state=level.getBlockState(pos.set(x,y,z));
if(state.is(Blocks.CHEST)&&level.getBlockEntity(pos) instanceof net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity chest&&chest.getLootTable()!=null)chests++;
if(state.is(Blocks.DISPENSER))traps++;
if(state.is(Blocks.MOSSY_COBBLESTONE)||state.is(Blocks.COBBLESTONE))masonry++;
}
require(chests==2&&traps==2&&masonry>300,"Native jungle temple incomplete "+chests+"/"+traps+"/"+masonry);
int lava=0,wallChecks=0;
for(int dx=-80;dx<=80;dx+=3)for(int dz=-80;dz<=80;dz+=3){
int x=i.centerX()+dx,z=i.centerZ()+dz;if(!f.lava(x,z))continue;
var at=new BlockPos(x,EastVolcano223.LAVA,z);level.getChunkAt(at);
require(level.getBlockState(at).is(Blocks.LAVA),"Native crater surface missing lava "+at);lava++;
var c=f.column(x,z);require(level.getBlockState(at.atY(c.top())).isSolidRender(),"Crater bottom breached");
for(int y=c.top()+1;y<=EastVolcano223.LAVA;y++)for(var dir:Direction.Plane.HORIZONTAL){
var q=at.relative(dir).atY(y);var state=level.getBlockState(q);require(state.is(Blocks.LAVA)||state.isSolidRender(),"Native lava wall open "+q);wallChecks++;
}
}
require(lava>350,"Crater too small");
int logs=0,bamboo=0,leaves=0,tallest=0,elevatedSoilRoots=0;var sampled=new HashSet<Long>();var habitats=new HashMap<String,Integer>();
for(String biome:List.of("east_giant_jungle"+i.generation(),"east_bamboo"+i.generation(),"east_sparse_jungle"+i.generation())){
int count=0;
for(int n=0;n<96&&count<8;n++){
double angle=n*Math.PI/48;int x=i.centerX()+(int)(Math.cos(angle)*310),z=i.centerZ()+(int)(Math.sin(angle)*310);
if(!f.biome(x,z).equals(biome))continue;
var cp=new net.minecraft.world.level.ChunkPos(x>>4,z>>4);if(!sampled.add(cp.pack()))continue;
var chunk=level.getChunk(cp.x(),cp.z());count++;habitats.merge(biome,1,Integer::sum);
for(int wx=cp.getMinBlockX();wx<=cp.getMaxBlockX();wx++)for(int wz=cp.getMinBlockZ();wz<=cp.getMaxBlockZ();wz++){
int ground=f.top(wx,wz),streak=0;
for(int y=ground+1;y<=ground+65;y++){
var state=chunk.getBlockState(pos.set(wx,y,wz));
if(y>ground+5&&state.is(net.minecraft.tags.BlockTags.DIRT)&&chunk.getBlockState(pos.above()).is(Blocks.JUNGLE_LOG)&&chunk.getBlockState(pos.above(2)).is(Blocks.JUNGLE_LOG))elevatedSoilRoots++;
if(state.is(Blocks.JUNGLE_LOG)){logs++;streak++;tallest=Math.max(tallest,streak);}else streak=0;
if(state.is(Blocks.BAMBOO))bamboo++;
if(state.is(Blocks.JUNGLE_LEAVES))leaves++;
}
}
}
require(count>=4,"Missing actual habitat samples "+biome);
}
require(logs>200&&leaves>1000&&bamboo>100&&tallest>=30,"Native vegetation missing: logs="+logs+" leaves="+leaves+" bamboo="+bamboo+" height="+tallest);
if(i.generation()==224)require(elevatedSoilRoots==0,"Trees planted on canopy: "+elevatedSoilRoots);
r.result().put("volcano",Map.of("lavaLevel",EastVolcano223.LAVA,"lavaColumnsChecked",lava,"wallChecks",wallChecks));
r.result().put("temple",Map.of("origin",temple.origin().toShortString(),"lootChests",chests,"dispensers",traps,"masonry",masonry));
r.result().put("vegetation",Map.of("chunks",sampled.size(),"habitats",habitats,"jungleLogs",logs,"jungleLeaves",leaves,"bamboo",bamboo,"tallestTrunk",tallest,"elevatedSoilRoots",elevatedSoilRoots));
r.result().put("relay",Map.of("position",relay.anchor().toShortString(),"checkedBlocks",relayBlocks,"preparedChunks",a.preparationChunks(i).size()));
var visit=new LinkedHashMap<String,Object>();visit.put("entrance",f.arrival().toShortString());visit.put("camera",f.arrival().offset(-32,115,0).toShortString());visit.put("temple",temple.origin().toShortString());visit.put("crater",new BlockPos(i.centerX(),EastVolcano223.LAVA,i.centerZ()).toShortString());visit.put("relay",relay.anchor().toShortString());r.result().put("visit",visit);finish(r);
}catch(Throwable e){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("EAST223_CHECK_FAILED",e);server.halt(false);}
}
private static void finish(Run r){run=null;r.result().put("readyForVisitMs",(System.nanoTime()-r.started())/1_000_000);WorldgenDiagnostics.writeReport(r.output(),r.result());}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -134,7 +134,7 @@ final class EcologySurvey176 {
try{Files.writeString(p.out().resolve("survey.json"),JSON.toJson(p.data())+"\n");}catch(java.io.IOException e){throw new IllegalStateException(e);}
p.result().put("survey",Map.of("path",p.out().toString(),"fluidTicks",240,"ponds",p.ponds().size()));
p.result().put("readyForVisitMs",(System.nanoTime()-p.started())/1_000_000);
PENDING.remove(server);WorldgenLab.writeReport(p.directory(),p.result());
PENDING.remove(server);WorldgenDiagnostics.writeReport(p.directory(),p.result());
}
private static Set<BlockPos> water(ServerLevel level,EcologyWater176.Pond p){
var sources=new HashSet<BlockPos>();int retained=0;
@@ -0,0 +1,81 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
/** Opt-in disposable native-world test: offers, FULL completion, a chained relay and reload. */
final class Expansion199Checks {
private static Run run;
private record Run(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh,
CompletableFuture<ExpansionIsland> request,ItemStack payment,int stage) {}
static void register(){ServerTickEvents.END_SERVER_TICK.register(Expansion199Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
if(adapter==null)throw new IllegalStateException("expansion199 profile required");
var session=ExpansionRuntime.session(level);
result.put("verificationScope","expansion199");
if(fresh){
var sites=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites();
var pos=sites.get(0).anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
var core=level.getBlockState(AnchorOffers189.CORE);
if(!core.is(OriginBlock.BLOCK)||!level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK))throw new AssertionError("Missing native root/core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var wrong=new ItemStack(Items.DIRT,64);
if(!RelayOffers199.offer(level,pos,wrong,()->true).isCompletedExceptionally()||wrong.getCount()!=64)throw new AssertionError("Wrong offering accepted");
var demand=AnchorOffers189.DEMANDS.get(0);var held=new ItemStack(demand.item(),demand.count()+1);
var request=RelayOffers199.offer(level,pos,held,()->true);
if(!RelayOffers199.offer(level,pos,held,()->true).isCompletedExceptionally())throw new AssertionError("Duplicate search accepted");
run=new Run(server,output,result,started,true,request,held,0);
}else{
if(session.islands().size()!=3)throw new AssertionError("Journal did not retain both expansions");
run=new Run(server,output,result,started,false,CompletableFuture.completedFuture(session.islands().get(2)),ItemStack.EMPTY,2);
}
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server()!=server)return;
try{
if(System.nanoTime()-r.started()>java.util.concurrent.TimeUnit.MINUTES.toNanos(8))throw new AssertionError("Expansion test timed out");
if(!r.request().isDone())return;
var admitted=r.request().join();var level=server.overworld();var session=ExpansionRuntime.session(level);
var current=session.island(admitted.id());
if(!current.status().equals("ready")){
if(r.stage()==1){
// Persist a partially prepared reservation; the warm run must complete it.
r.result().put("reservedChild",current.id());finish(r);return;
}
if(session.progress().contains(": ")&&!session.progress().matches(".*: [0-9]+/[0-9]+"))throw new AssertionError(session.progress());
return;
}
var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());var relay=adapter.relay(current);
if(!level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK))throw new AssertionError("Ready before next relay exists");
if(r.stage()==0){
if(r.payment().getCount()!=1)throw new AssertionError("Offer charged incorrectly");
var rootSite=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().get(0).anchor();
if(RelayOffers199.offer(level,rootSite,r.payment(),()->true).join().id().equals(current.id())&&r.payment().getCount()!=1)throw new AssertionError("Repeated offer charged");
r.result().put("firstExpansion",Map.of("id",current.id(),"x",current.centerX(),"z",current.centerZ(),"relayY",relay.getY()));
int sector=level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR);var demand=AnchorOffers189.DEMANDS.get(sector);
var held=new ItemStack(demand.item(),demand.count()+1);
var request=RelayOffers199.offer(level,relay,held,()->true);
run=new Run(server,r.output(),r.result(),r.started(),true,request,held,1);
}else{
int columns=0,solid=0;int low=1600,high=0;
for(int x=-64;x<=64;x+=16)for(int z=-64;z<=64;z+=16){
var chunk=level.getChunk((current.centerX()+x)>>4,(current.centerZ()+z)>>4);columns++;
for(int y=0;y<384;y++)if(!chunk.getBlockState(new BlockPos(current.centerX()+x,y,current.centerZ()+z)).isAir()){solid++;low=Math.min(low,y);high=Math.max(high,y);}
}
if(solid<columns*4||solid>columns*110||low<140||high>325)throw new AssertionError("Unexpected sheet terrain "+solid+" / "+columns+" y="+low+".."+high);
r.result().put("resumedExpansion",Map.of("id",current.id(),"columns",columns,"solid",solid,"minY",low,"maxY",high));
finish(r);
}
}catch(Throwable e){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("EXPANSION199_CHECK_FAILED",e);server.halt(false);}
}
private static void finish(Run r){run=null;r.result().put("readyForVisitMs",(System.nanoTime()-r.started())/1_000_000);WorldgenDiagnostics.writeReport(r.output(),r.result());}
}
@@ -0,0 +1,38 @@
package fr.koka.sanctuarytest;
import java.util.*;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.levelgen.RandomState;
/** Opt-in laboratory verification; never runs during ordinary world creation. */
final class Gallery198Checks {
static List<Map<String,Object>> check(ServerLevel level) {
var rows=new ArrayList<Map<String,Object>>();
var biomes=((AdventureBiomes180)level.getChunkSource().getGenerator().getBiomeSource()).collectPossibleBiomes().toList();
for(var size:SharedIsland196.Size.values())for(long seed:new long[]{0,17,42,4736390610738281858L,Long.MIN_VALUE}) {
var settings=level.registryAccess().lookupOrThrow(Registries.NOISE_SETTINGS)
.getOrThrow(ResourceKey.create(Registries.NOISE_SETTINGS,size.id())).value();
var random=RandomState.create(level.registryAccess().lookupOrThrow(Registries.NOISE),seed,settings);
var field=(ReliefEcology177.Field)random.getSampler(settings.noiseRouter().finalDensity());
var current=new AdventureBiomes180(biomes,true,true,true,true,true);current.bind(seed,field);
var plan=Cavern183.plan(current);
var centre=plan.rooms().getFirst();
if(centre.x()!=0||centre.z()!=0||centre.y()<32||centre.y()>276)
throw new AssertionError("Invalid mandatory gallery: "+size+" "+seed+" "+centre);
var repeat=new AdventureBiomes180(biomes,true,true,true,true,true);repeat.bind(seed,field);
if(!plan.equals(Cavern183.plan(repeat)))throw new AssertionError("Non-deterministic gallery");
var historical=new AdventureBiomes180(biomes,true,true,true,true);historical.bind(seed,field);
boolean fallback=false;
try {
if(!plan.equals(Cavern183.plan(historical)))throw new AssertionError("Previously valid gallery changed");
} catch(IllegalStateException e) {
if(!"No supported central gallery floor".equals(e.getMessage()))throw e;
fallback=true;
}
rows.add(Map.of("size",size.name(),"seed",seed,"floorY",centre.y(),"newFallback",fallback));
}
return rows;
}
}
@@ -0,0 +1,64 @@
package fr.koka.sanctuarytest;
import com.google.gson.JsonParser;
import fr.koka.sanctuary.SanctuaryMod;
import java.nio.file.*;
import java.util.List;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.minecraft.client.gui.components.*;
import net.minecraft.client.gui.screens.BackupConfirmScreen;
import net.minecraft.client.input.KeyEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.storage.LevelResource;
/** Explicit launcher option for a fresh disposable visit; no photos, camera control or ordinary-world prompts. */
final class LabVisit200 {
private static boolean confirmed,identity,ready;
static void register(){
var argument=System.getProperty("sanctuary.labVisit200");if(argument==null)return;
try{
var manifest=Path.of(argument).toAbsolutePath().normalize();var run=manifest.getParent();
var data=JsonParser.parseString(Files.readString(manifest)).getAsJsonObject();var world=data.get("world").getAsString();var revision=Integer.parseInt(world.split("-")[2]);
if(!world.matches("Sanctuary-(North-(20[012345678]|215)|Diagonal-(225|226|227|228|229|230|231)|East-(223|224)|West-(217|218|219|220|221)|South-(209|210|211|212|213|214|215|216))-[0-9-]+")||!run.toString().contains("/build/worldgen-lab/")||!data.get("freshVisit").getAsBoolean())throw new IllegalArgumentException("Expected disposable North visit");
ScreenEvents.AFTER_INIT.register((mc,screen,w,h)->{
if(!mc.gameDirectory.toPath().toAbsolutePath().normalize().equals(run.resolve("client")))throw new IllegalStateException("Visit directory mismatch");
if(!confirmed&&screen instanceof BackupConfirmScreen&&screen.getTitle().getString().equals(Component.translatable("selectWorld.backupQuestion.experimental").getString())){
for(var child:screen.children())if(child instanceof Button b&&b.getMessage().getString().equals(Component.translatable("selectWorld.backupJoinSkipButton").getString())){
confirmed=true;mc.execute(()->{if(mc.gui.screen()==screen)b.onPress(new KeyEvent(257,0,0));});break;
}
}
if(!identity&&screen instanceof fr.koka.sanctuary.client.HelloWorldScreen){
identity=true;mc.execute(()->{
if(mc.gui.screen()!=screen)return;var enter=new KeyEvent(257,0,0);
for(var suffix:List.of("$ColorButton","$StarterSlot"))for(var child:screen.children())if(child instanceof Button b&&child.getClass().getName().endsWith(suffix)&&b.active){b.onPress(enter);break;}
for(var child:screen.children())if(child instanceof EditBox box&&box.getMessage().getString().equals(Component.translatable("sanctuary.starter.name").getString()))box.setValue("Labo");
for(var child:screen.children())if(child instanceof Button b&&b.active&&b.getMessage().getString().equals(fr.koka.sanctuary.progression.ProgressionService.label("enter").getString())){b.onPress(enter);break;}
});
}
});
ClientTickEvents.END_CLIENT_TICK.register(mc->{
if(ready||mc.player==null||mc.level==null||mc.gui.screen()!=null||mc.getSingleplayerServer()==null)return;
var server=mc.getSingleplayerServer();
if(!server.getWorldPath(LevelResource.ROOT).toAbsolutePath().normalize().equals(run.resolve("client/saves").resolve(world)))throw new IllegalStateException("Wrong visit world");
if(SharedIsland196.revision(server.overworld().getChunkSource().getGenerator())!=revision)throw new IllegalStateException("Wrong visit revision");
if(revision==221){
var state=fr.koka.sanctuary.building.YellowStone.BLOCK.defaultBlockState();
var tints=mc.getBlockColors().getTintSources(state);
if(tints.size()!=1||tints.getFirst().colorInWorld(state,mc.level,mc.player.blockPosition())!=fr.koka.sanctuary.building.YellowStone.TINT)throw new IllegalStateException("Yellow stone tint missing");
var parts=new java.util.ArrayList<net.minecraft.client.renderer.block.dispatch.BlockStateModelPart>();
mc.getModelManager().getBlockStateModelSet().get(state).collectParts(net.minecraft.util.RandomSource.create(42),parts);
int faces=0;
for(var part:parts)for(var direction:net.minecraft.core.Direction.values())for(var quad:part.getQuads(direction)){
var material=quad.materialInfo();
if(material.tintIndex()!=0||!material.sprite().contents().name().toString().equals("minecraft:block/stone"))throw new IllegalStateException("Yellow stone model/texture missing");
faces++;
}
if(faces!=6)throw new IllegalStateException("Yellow stone model is incomplete");
SanctuaryMod.LOGGER.info("YELLOW_STONE221_CLIENT_PASS faces={} tint={}",faces,Integer.toHexString(fr.koka.sanctuary.building.YellowStone.TINT));
}
ready=true;SanctuaryMod.LOGGER.info("{}{}_VISIT_OPEN world={} player={}",world.split("-")[1].toUpperCase(java.util.Locale.ROOT),revision,world,mc.player.blockPosition());
});
}catch(Exception e){throw new IllegalStateException("Invalid North visit manifest",e);}
}
}
@@ -0,0 +1,110 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
/** Opt-in fresh-world integration: actual offering, interrupted preparation, village and frozen lake. */
final class North200Checks {
private record Run(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh,int revision,CompletableFuture<ExpansionIsland> request,ItemStack payment) {}
private static Run run;
static void register(){ServerTickEvents.END_SERVER_TICK.register(North200Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
int revision=Boolean.getBoolean("sanctuary.worldgenLab.north208")?208:Boolean.getBoolean("sanctuary.worldgenLab.north207")?207:Boolean.getBoolean("sanctuary.worldgenLab.north206")?206:Boolean.getBoolean("sanctuary.worldgenLab.north205")?205:Boolean.getBoolean("sanctuary.worldgenLab.north204")?204:Boolean.getBoolean("sanctuary.worldgenLab.north203")?203:Boolean.getBoolean("sanctuary.worldgenLab.north202")?202:Boolean.getBoolean("sanctuary.worldgenLab.north201")?201:200;
require(adapter!=null&&adapter.rootGeneration()==revision,"Wrong profile");
var session=ExpansionRuntime.session(level);result.put("verificationScope","north"+revision);
if(fresh){
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==0).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing north anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var wrong=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,wrong,()->true).isCompletedExceptionally()&&wrong.getCount()==64,"Wrong offer accepted");
var payment=new ItemStack(Items.STONE,33);var request=RelayOffers199.offer(level,pos,payment,()->true);
require(RelayOffers199.offer(level,pos,payment,()->true).isCompletedExceptionally(),"Duplicate search accepted");
result.put("anchor",pos.toShortString());run=new Run(server,output,result,started,true,revision,request,payment);
}else{
require(session.islands().size()==2,"Reservation not restored");
run=new Run(server,output,result,started,false,revision,CompletableFuture.completedFuture(session.islands().get(1)),ItemStack.EMPTY);
}
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server()!=server)return;
try{
require(System.nanoTime()-r.started()<java.util.concurrent.TimeUnit.MINUTES.toNanos(8),"Timeout");
if(!r.request().isDone())return;
var admitted=r.request().join();var level=server.overworld();var session=ExpansionRuntime.session(level);
require(admitted.generation()==r.revision()&&admitted.diameter()==(r.revision()>=201?1024:2048)&&admitted.direction().equals("north")&&admitted.climate().equals("glacial"),"Wrong region identity");
r.result().put("expansion",Map.of("id",admitted.id(),"x",admitted.centerX(),"z",admitted.centerZ(),"diameter",admitted.diameter()));
if(r.fresh()){
require(r.payment().getCount()==1,"Wrong charge");
require(session.island(admitted.id()).status().equals("reserved"),"Expected interruption during preparation");
r.result().put("interruptedProgress",session.progress());finish(r);return;
}
var island=session.island(admitted.id());
if(!island.status().equals("ready")){
require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;
}
var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());var village=adapter.village(island);
require(adapter.preparationChunks(island).size()<=64,"Unbounded preparation");
var relay=village.relay();level.getChunkAt(relay);require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK),"No continuation relay");
require(level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==0,"Relay identity changed");
int beds=0,cellars=0;
for(var house:village.houses()){
var centre=house.at(3,0,3);level.getChunkAt(centre);
for(int x=0;x<7;x++)for(int z=0;z<8;z++)if(level.getBlockState(house.at(x,1,z)).getBlock() instanceof BedBlock)beds++;
var trap=house.at(3,0,5);
if(house.cellar()){
require(level.getBlockState(trap).getBlock() instanceof TrapDoorBlock,"No secret hatch");
for(int y=-1;y>=-16;y--)require(level.getBlockState(house.at(3,y,5)).is(Blocks.LADDER),"Broken cellar ladder at "+house.at(3,y,5));
require(level.getBlockState(house.at(1,-17,4)).is(Blocks.CHEST),"No cellar chest");
require(level.getBlockState(house.at(5,-16,4)).is(Blocks.BREWING_STAND),"No curing station");cellars++;
}else require(level.getBlockState(trap).is(Blocks.SNOW_BLOCK),"Extra secret hatch");
}
require(beds==10&&cellars==1,"Village incomplete: beds="+beds+" cellars="+cellars);
r.result().put("village",Map.of("arrival",village.arrival().toShortString(),"relay",relay.toShortString(),"igloos",village.houses().size(),"cellars",cellars));
if(r.revision()==208){North208Checks.verify(level,island,village,r.result());finish(r);return;}
if(r.revision()==207){North207Checks.verify(level,island,village,r.result());finish(r);return;}
if(r.revision()==206){North206Checks.verify(level,island,village,r.result());finish(r);return;}
if(r.revision()==205){North205Checks.verify(level,island,village,r.result());finish(r);return;}
if(r.revision()==204){North204Checks.verify(level,island,village,r.result());finish(r);return;}
var f=NorthTerrain.field(island);var lake=f.lakes().getFirst();int reach=(int)(lake.radius()*1.75)+3;
for(int x=(lake.x()-reach)>>4;x<=(lake.x()+reach)>>4;x++)for(int z=(lake.z()-reach)>>4;z<=(lake.z()+reach)>>4;z++)level.getChunk(x,z);
int ice=0,water=0;
for(int x=lake.x()-reach;x<=lake.x()+reach;x++)for(int z=lake.z()-reach;z<=lake.z()+reach;z++){
var c=f.column(x,z);if(c.water()<0)continue;
var lid=new BlockPos(x,c.water(),z);require(level.getBlockState(lid).is(Blocks.ICE),"Missing frozen lid "+lid);ice++;
for(int y=(int)Math.floor(c.top())+1;y<c.water();y++){
var p=new BlockPos(x,y,z);require(!level.getBlockState(p).getFluidState().isEmpty(),"Dry lake "+p);water++;
for(var n:List.of(p.north(),p.south(),p.east(),p.west(),p.below()))require(!level.getBlockState(n).isAir(),"Lake leak into air "+n);
}
}
require(ice>800&&water>2000,"Missing lake");r.result().put("frozenLake",Map.of("x",lake.x(),"y",lake.level(),"z",lake.z(),"ice",ice,"water",water));
// A few actual columns in distant peaks: newly explored terrain after ready, not a blanket pre-generation.
int frozen=0,cavities=0;double highest=0;BlockPos peak=null;
for(int x=-750;x<=750;x+=50)for(int z=-750;z<=750;z+=50){var c=f.column(island.centerX()+x,island.centerZ()+z);double score=c.top();if(r.revision()==203){var cover=NorthTerrain203.field(island).cover(island.centerX()+x,island.centerZ()+z);if(cover.caveHigh()-cover.caveLow()<12)continue;score=cover.caveHigh()-cover.caveLow()+c.top()*.01;}if(c.edge()>100&&score>highest){highest=score;peak=new BlockPos(island.centerX()+x,(int)c.top(),island.centerZ()+z);}}
for(int dx=-16;dx<=16;dx+=4)for(int dz=-16;dz<=16;dz+=4){
int x=peak.getX()+dx,z=peak.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);
for(int y=(int)c.bottom()+12;y<c.top()-12;y++){
var state=chunk.getBlockState(new BlockPos(x,y,z));if(state.is(Blocks.BLUE_ICE)||state.is(Blocks.PACKED_ICE))frozen++;if(state.isAir())cavities++;
}
}
require(frozen>20&&cavities>30,"No native ice cavern: "+frozen+"/"+cavities);
r.result().put("iceCavern",Map.of("peak",peak.toShortString(),"ice",frozen,"air",cavities));
if(r.revision()==203)North203Checks.verify(level,island,village,r.result());
if(r.revision()==202)North202Checks.verify(level,island,village,r.result());
if(r.revision()==201)North201Checks.verify(level,island,village,r.result());
finish(r);
}catch(Throwable e){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("NORTH200_CHECK_FAILED",e);server.halt(false);}
}
private static void finish(Run r){run=null;r.result().put("readyForVisitMs",(System.nanoTime()-r.started())/1_000_000);WorldgenDiagnostics.writeReport(r.output(),r.result());}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,44 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
/** Verify actual native decorations and visible surfaces, beyond biome IDs or analytic density. */
final class North201Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain201.field(island);var wood=f.woodland();int logs=0,leaves=0;var trunks=new HashSet<Long>();
for(int dx=-24;dx<=24;dx++)for(int dz=-24;dz<=24;dz++){
int x=wood.getX()+dx,z=wood.getZ()+dz;var c=f.column(x,z);var chunk=level.getChunk(x>>4,z>>4);
for(int y=(int)c.top()-2;y<=c.top()+24;y++){
var p=new BlockPos(x,y,z);var b=chunk.getBlockState(p);
if(b.is(Blocks.SPRUCE_LOG)){logs++;trunks.add(((long)x<<32)^(z&0xffffffffL));}
if(b.is(Blocks.SPRUCE_LEAVES))leaves++;
}
}
require(trunks.size()>=10&&logs>=50&&leaves>=100,"Native woodland absent: "+trunks.size()+" trunks, "+logs+" logs, "+leaves+" leaves");
result.put("nativeWoodland",Map.of("centre",wood.toShortString(),"trunks",trunks.size(),"logs",logs,"leaves",leaves));
int iceAbove=0,tallest=0,spikedColumns=0;
int cx=island.centerX()-145,cz=island.centerZ()-115;
for(int dx=-32;dx<=32;dx++)for(int dz=-32;dz<=32;dz++){
int x=cx+dx,z=cz+dz;var c=f.column(x,z);var chunk=level.getChunk(x>>4,z>>4);int height=0;
for(int y=(int)Math.ceil(c.top())+2;y<c.top()+64;y++)if(chunk.getBlockState(new BlockPos(x,y,z)).is(Blocks.PACKED_ICE)){iceAbove++;height=Math.max(height,y-(int)Math.floor(c.top()));}
if(height>=5)spikedColumns++;tallest=Math.max(tallest,height);
}
require(iceAbove>=100&&tallest>=7&&spikedColumns>=15,"Native ice spikes absent: "+iceAbove+" ice, max height "+tallest);
result.put("nativeIceSpikes",Map.of("x",cx,"z",cz,"iceAboveTerrain",iceAbove,"tallest",tallest,"columns",spikedColumns));
int visibleIce=0,snowCovered=0;var lake=f.lakes().getFirst();
for(int dx=-45;dx<=45;dx++)for(int dz=-45;dz<=45;dz++){
int x=lake.x()+dx,z=lake.z()+dz;var c=f.column(x,z);if(c.water()<0)continue;
var p=new BlockPos(x,c.water(),z);
if(level.getBlockState(p).is(Blocks.ICE)&&level.getBlockState(p.above()).isAir())visibleIce++;
if(level.getBlockState(p.above()).is(Blocks.SNOW)||level.getBlockState(p.above()).is(Blocks.SNOW_BLOCK))snowCovered++;
}
require(visibleIce>2500&&snowCovered<visibleIce/20,"Lake hidden by snow: "+visibleIce+" visible / "+snowCovered+" hidden");
require(Math.hypot(village.arrival().getX()-lake.x(),village.arrival().getZ()-lake.z())<220,"Village too far from lake");
result.put("visibleLake",Map.of("ice",visibleIce,"snowCovered",snowCovered));
}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,56 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
/** Inspect actual native vegetation, snow and exposed rock in a fresh 202 world. */
final class North202Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain202.field(island);var wood=f.sample(NorthTerrain202.Surface.OLD_GROWTH);
int logs=0,leaves=0,podzol=0,tallestTree=0;var trunks=new HashSet<Long>();
for(int dx=-32;dx<=32;dx++)for(int dz=-32;dz<=32;dz++){
int x=wood.getX()+dx,z=wood.getZ()+dz;var c=f.column(x,z);var chunk=level.getChunk(x>>4,z>>4);int trunk=0;
for(int y=(int)c.top()-2;y<=c.top()+40;y++){
var state=chunk.getBlockState(new BlockPos(x,y,z));
if(state.is(Blocks.SPRUCE_LOG)){logs++;trunk++;trunks.add(((long)x<<32)^(z&0xffffffffL));}
if(state.is(Blocks.SPRUCE_LEAVES))leaves++;
if(state.is(Blocks.PODZOL))podzol++;
}
tallestTree=Math.max(tallestTree,trunk);
}
int wide=0;for(long key:trunks){int x=(int)(key>>32),z=(int)key;if(trunks.contains(((long)(x+1)<<32)^(z&0xffffffffL))&&trunks.contains(((long)x<<32)^((z+1)&0xffffffffL))&&trunks.contains(((long)(x+1)<<32)^((z+1)&0xffffffffL)))wide++;}
require(wide>0&&tallestTree>=18&&logs>100&&leaves>100&&podzol>100,"Native giant spruce absent: "+wide+" wide, "+tallestTree+" tall, "+logs+" logs");
result.put("nativeGiantTaiga",Map.of("centre",wood.toShortString(),"wideTrunks",wide,"tallestTrunk",tallestTree,"logs",logs,"leaves",leaves,"podzol",podzol));
var spikes=f.sample(NorthTerrain202.Surface.SPIKES);int iceAbove=0,tallest=0;
for(int dx=-40;dx<=40;dx++)for(int dz=-40;dz<=40;dz++){
int x=spikes.getX()+dx,z=spikes.getZ()+dz;var c=f.column(x,z);var chunk=level.getChunk(x>>4,z>>4);
for(int y=(int)Math.ceil(c.top())+3;y<c.top()+64;y++)if(chunk.getBlockState(new BlockPos(x,y,z)).is(Blocks.PACKED_ICE)){iceAbove++;tallest=Math.max(tallest,y-(int)c.top());}
}
require(iceAbove>100&&tallest>=7,"Vanilla ice spikes absent: "+iceAbove+" / "+tallest);
result.put("nativeIceSpikes",Map.of("centre",spikes.toShortString(),"iceAboveTerrain",iceAbove,"tallest",tallest));
int snow=0,checked=0;
for(int dx=-36;dx<=36;dx+=3)for(int dz=-36;dz<=36;dz+=3){
int x=village.arrival().getX()+dx,z=village.arrival().getZ()+dz;if(village.nearHouse(x,z))continue;
require(f.snowyPlain(x,z),"Igloos leave the snow meadow");checked++;
int top=(int)Math.floor(f.column(x,z).top());
for(int y=top-2;y<=top+3;y++)if(level.getBlockState(new BlockPos(x,y,z)).is(Blocks.SNOW_BLOCK)||level.getBlockState(new BlockPos(x,y,z)).is(Blocks.SNOW)){snow++;break;}
}
require(checked>100&&snow>checked*.90,"Village not covered by snow: "+snow+" / "+checked);
result.put("snowyVillageGround",Map.of("checked",checked,"snow",snow));
int rock=0,exteriorIce=0;
for(int n=0;n<16;n++){
double a=n*Math.PI/8;int x=island.centerX()+(int)(Math.sin(a)*island.radius()*.9),z=island.centerZ()+(int)(Math.cos(a)*island.radius()*.9);var c=f.column(x,z);
var chunk=level.getChunk(x>>4,z>>4);
for(int y=(int)c.bottom()-6;y<c.top()-8;y++){
var state=chunk.getBlockState(new BlockPos(x,y,z));if(state.is(Blocks.STONE)||state.is(Blocks.DEEPSLATE))rock++;
if(state.is(Blocks.BLUE_ICE)||state.is(Blocks.PACKED_ICE))exteriorIce++;
}
}
require(rock>100&&exteriorIce==0,"Exterior ice coating: "+exteriorIce);
result.put("exteriorRock",Map.of("rock",rock,"ice",exteriorIce));
}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,62 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
/** Inspect actual native vegetation, snow and exposed rock in a fresh 203 world. */
final class North203Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain203.field(island);var wood=f.sample(NorthTerrain203.Surface.OLD_GROWTH);
int logs=0,leaves=0,podzol=0,tallestTree=0;var trunks=new HashSet<Long>();
for(int dx=-32;dx<=32;dx++)for(int dz=-32;dz<=32;dz++){
int x=wood.getX()+dx,z=wood.getZ()+dz;var c=f.column(x,z);var chunk=level.getChunk(x>>4,z>>4);int trunk=0;
for(int y=(int)c.top()-2;y<=c.top()+68;y++){
var state=chunk.getBlockState(new BlockPos(x,y,z));
if(state.is(Blocks.SPRUCE_LOG)){logs++;trunk++;trunks.add(((long)x<<32)^(z&0xffffffffL));}
if(state.is(Blocks.SPRUCE_LEAVES))leaves++;
if(state.is(Blocks.PODZOL))podzol++;
}
tallestTree=Math.max(tallestTree,trunk);
}
int wide=0;for(long key:trunks){int x=(int)(key>>32),z=(int)key;if(trunks.contains(((long)(x+1)<<32)^(z&0xffffffffL))&&trunks.contains(((long)x<<32)^((z+1)&0xffffffffL))&&trunks.contains(((long)(x+1)<<32)^((z+1)&0xffffffffL)))wide++;}
require(wide>0&&tallestTree>=40&&tallestTree<=64&&logs>100&&leaves>100&&podzol>100,"Native giant spruce absent: "+wide+" wide, "+tallestTree+" tall, "+logs+" logs");
result.put("nativeGiantTaiga",Map.of("centre",wood.toShortString(),"wideTrunks",wide,"tallestTrunk",tallestTree,"logs",logs,"leaves",leaves,"podzol",podzol));
var spikes=f.sample(NorthTerrain203.Surface.SPIKES);int iceAbove=0,tallest=0;var materials=new HashMap<String,Integer>();
for(int dx=-40;dx<=40;dx++)for(int dz=-40;dz<=40;dz++){
int x=spikes.getX()+dx,z=spikes.getZ()+dz;var c=f.column(x,z);var chunk=level.getChunk(x>>4,z>>4);
for(int y=(int)Math.floor(c.top())-4;y<=c.top();y++){
var b=chunk.getBlockState(new BlockPos(x,y,z)).getBlock();
if(b==Blocks.STONE||b==Blocks.ICE||b==Blocks.PACKED_ICE||b==Blocks.BLUE_ICE||b==Blocks.SNOW_BLOCK)
materials.merge(net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(b).toString(),1,Integer::sum);
}
for(int y=(int)Math.ceil(c.top())+3;y<c.top()+64;y++)if(chunk.getBlockState(new BlockPos(x,y,z)).is(Blocks.PACKED_ICE)){iceAbove++;tallest=Math.max(tallest,y-(int)c.top());}
}
require(iceAbove>100&&tallest>=7,"Vanilla ice spikes absent: "+iceAbove+" / "+tallest);
require(materials.size()==5,"Missing summit material: "+materials);result.put("summitMaterials",materials);
result.put("nativeIceSpikes",Map.of("centre",spikes.toShortString(),"iceAboveTerrain",iceAbove,"tallest",tallest));
int layers=0,checked=0;
for(int dx=-36;dx<=36;dx+=3)for(int dz=-36;dz<=36;dz+=3){
int x=village.arrival().getX()+dx,z=village.arrival().getZ()+dz;if(village.nearHouse(x,z))continue;
require(f.snowyPlain(x,z),"Igloos leave their meadow");checked++;
int top=(int)Math.floor(f.column(x,z).top());
for(int y=top-2;y<=top+3;y++)if(level.getBlockState(new BlockPos(x,y,z)).is(Blocks.SNOW)){layers++;break;}
}
require(checked>100&&layers==0,"Additive snow returned: "+layers);
result.put("meadowWithoutSnowPass",Map.of("checked",checked,"snowLayers",layers));
int rock=0,exteriorIce=0;
for(int n=0;n<16;n++){
double a=n*Math.PI/8;int x=island.centerX()+(int)(Math.sin(a)*island.radius()*.9),z=island.centerZ()+(int)(Math.cos(a)*island.radius()*.9);var c=f.column(x,z);
var chunk=level.getChunk(x>>4,z>>4);
for(int y=(int)c.bottom()-6;y<c.top()-8;y++){
var state=chunk.getBlockState(new BlockPos(x,y,z));if(state.is(Blocks.STONE)||state.is(Blocks.DEEPSLATE))rock++;
if(state.is(Blocks.BLUE_ICE)||state.is(Blocks.PACKED_ICE))exteriorIce++;
}
}
require(rock>100&&exteriorIce==0,"Exterior ice coating: "+exteriorIce);
result.put("exteriorRock",Map.of("rock",rock,"ice",exteriorIce));
}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -0,0 +1,56 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
/** Native checks of the real Peaks volume and retained northern ecology, on new development worlds. */
final class North204Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain204.field(island);
double lo=999,hi=0,thickness=0;var covers=new EnumMap<NorthTerrain204.Surface,Integer>(NorthTerrain204.Surface.class);
BlockPos cave=null;double deepest=-1;
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=island.centerX()+dx,z=island.centerZ()+dz;var c=f.column(x,z);if(c.top()<0||c.edge()<80)continue;
lo=Math.min(lo,c.top());hi=Math.max(hi,c.top());thickness=Math.max(thickness,c.top()-c.bottom());
var cover=f.cover(x,z);covers.merge(cover.surface(),1,Integer::sum);
double room=cover.caveHigh()-cover.caveLow();if(room>deepest){deepest=room;cave=new BlockPos(x,(int)c.top(),z);}
}
require(hi-lo>60&&thickness>100,"Peaks collapsed into a sheet: "+lo+".."+hi+", thickness="+thickness);
result.put("peaksRelief",Map.of("minTop",lo,"maxTop",hi,"maxThickness",thickness,"surfaces",covers));
var wood=f.sample(NorthTerrain204.Surface.OLD_GROWTH);int logs=0,leaves=0,tallest=0,podzol=0;
for(int dx=-32;dx<=32;dx++)for(int dz=-32;dz<=32;dz++){
int x=wood.getX()+dx,z=wood.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);int trunk=0;
for(int y=Math.max(1,(int)c.top()-20);y<=c.top()+80;y++){
var b=chunk.getBlockState(new BlockPos(x,y,z));
if(b.is(Blocks.SPRUCE_LOG)){logs++;trunk++;}if(b.is(Blocks.SPRUCE_LEAVES))leaves++;if(b.is(Blocks.PODZOL))podzol++;
}
tallest=Math.max(tallest,trunk);
}
require(tallest>=40&&logs>100&&leaves>100&&podzol>50,"Giant taiga absent: "+tallest+" / "+logs+" / "+podzol);
result.put("nativeGiantTaiga",Map.of("centre",wood.toShortString(),"tallestTrunk",tallest,"logs",logs,"leaves",leaves,"podzol",podzol));
int ice=0,air=0;
require(cave!=null&&deepest>20,"No covered cave volume");
for(int dx=-24;dx<=24;dx+=4)for(int dz=-24;dz<=24;dz+=4){
int x=cave.getX()+dx,z=cave.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.cover(x,z);
for(int y=c.caveLow();y<=c.caveHigh();y++){
var b=chunk.getBlockState(new BlockPos(x,y,z));if(b.is(Blocks.PACKED_ICE)||b.is(Blocks.BLUE_ICE))ice++;if(b.isAir())air++;
}
}
require(ice>20&&air>30,"Native ice cavern absent: "+ice+" / "+air);
result.put("iceCavern",Map.of("peak",cave.toShortString(),"ice",ice,"air",air));
var peaks=f.sample(NorthTerrain204.Surface.GLACIER);var materials=new HashMap<String,Integer>();
for(int dx=-24;dx<=24;dx+=2)for(int dz=-24;dz<=24;dz+=2){
int x=peaks.getX()+dx,z=peaks.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);
int y=chunk.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.OCEAN_FLOOR,x&15,z&15);
for(int k=y-6;k<=y;k++){
var b=chunk.getBlockState(new BlockPos(x,k,z)).getBlock();materials.merge(net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(b).toString(),1,Integer::sum);
}
}
require(materials.containsKey("minecraft:packed_ice")||materials.containsKey("minecraft:blue_ice"),"No glacier");
result.put("glacier",Map.of("centre",peaks.toShortString(),"materials",materials));
}
private static void require(boolean condition,String message){if(!condition)throw new AssertionError(message);}
}
@@ -0,0 +1,82 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
/** Native checks of the unwarped noise volume and retained northern ecology, on new development worlds. */
final class North205Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain205.field(island);
double lo=999,hi=0,thickness=0;var covers=new EnumMap<NorthTerrain205.Surface,Integer>(NorthTerrain205.Surface.class);
BlockPos cave=null;double deepest=-1;
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=island.centerX()+dx,z=island.centerZ()+dz;var c=f.column(x,z);if(c.top()<0||c.edge()<80)continue;
lo=Math.min(lo,c.top());hi=Math.max(hi,c.top());thickness=Math.max(thickness,c.top()-c.bottom());
var cover=f.cover(x,z);covers.merge(cover.surface(),1,Integer::sum);
// Raw 3D noise does not guarantee a cave in the thickest mountain column.
// Locate a genuinely empty covered pocket, then verify its blocks in native chunks.
int open=0;for(int y=cover.caveLow()+4;y<cover.caveHigh()-4;y+=4)if(f.density(x,y,z)<-.05)open++;
double room=cover.caveHigh()-cover.caveLow();double score=open*100+room*.01;
if(open>8&&room>20&&score>deepest){deepest=score;cave=new BlockPos(x,(int)c.top(),z);}
}
require(hi-lo>60&&thickness>100,"Noise collapsed into a sheet: "+lo+".."+hi+", thickness="+thickness);
result.put("noiseRelief",Map.of("minTop",lo,"maxTop",hi,"maxThickness",thickness,"surfaces",covers));
var wood=f.sample(NorthTerrain205.Surface.OLD_GROWTH);int logs=0,leaves=0,tallest=0,podzol=0;
for(int dx=-32;dx<=32;dx++)for(int dz=-32;dz<=32;dz++){
int x=wood.getX()+dx,z=wood.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);int trunk=0;
for(int y=Math.max(1,(int)c.top()-20);y<=c.top()+80;y++){
var b=chunk.getBlockState(new BlockPos(x,y,z));
if(b.is(Blocks.SPRUCE_LOG)){logs++;trunk++;}if(b.is(Blocks.SPRUCE_LEAVES))leaves++;if(b.is(Blocks.PODZOL))podzol++;
}
tallest=Math.max(tallest,trunk);
}
require(tallest>=40&&logs>100&&leaves>100&&podzol>50,"Giant taiga absent: "+tallest+" / "+logs+" / "+podzol);
result.put("nativeGiantTaiga",Map.of("centre",wood.toShortString(),"tallestTrunk",tallest,"logs",logs,"leaves",leaves,"podzol",podzol));
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("NORTH205_GEOGRAPHY {} / {}",result.get("noiseRelief"),result.get("nativeGiantTaiga"));
int ice=0,air=0;
require(cave!=null&&deepest>20,"No covered cave volume");
for(int dx=-24;dx<=24;dx+=4)for(int dz=-24;dz<=24;dz+=4){
int x=cave.getX()+dx,z=cave.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.cover(x,z);
for(int y=c.caveLow();y<=c.caveHigh();y++){
var b=chunk.getBlockState(new BlockPos(x,y,z));if(b.is(Blocks.PACKED_ICE)||b.is(Blocks.BLUE_ICE))ice++;if(b.isAir())air++;
}
}
require(ice>20&&air>30,"Native ice cavern absent: "+ice+" / "+air);
result.put("iceCavern",Map.of("peak",cave.toShortString(),"ice",ice,"air",air));
var peaks=f.sample(NorthTerrain205.Surface.GLACIER);var materials=new HashMap<String,Integer>();
for(int dx=-24;dx<=24;dx+=2)for(int dz=-24;dz<=24;dz+=2){
int x=peaks.getX()+dx,z=peaks.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);
int y=chunk.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.OCEAN_FLOOR,x&15,z&15);
for(int k=y-6;k<=y;k++){
var b=chunk.getBlockState(new BlockPos(x,k,z)).getBlock();materials.merge(net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(b).toString(),1,Integer::sum);
}
}
result.put("glacier",Map.of("centre",peaks.toShortString(),"materials",materials));
// The lower, unwarped relief also uses normal ice; a glacier need not be blue ice.
int glacierIce=materials.getOrDefault("minecraft:ice",0)+materials.getOrDefault("minecraft:packed_ice",0)+materials.getOrDefault("minecraft:blue_ice",0);
require(glacierIce>50,"No native glacier ice: "+materials);
// Compare stored biome cells on both sides of real chunk edges with the same world field.
// A resolver snapshot or request-order error must not leave one chunk on a different palette.
int checked=0,mismatches=0;
for(var centre:List.of(wood,peaks,village.arrival())){
int cx=centre.getX()>>4,cz=centre.getZ()>>4;
for(int dx=-1;dx<=1;dx++)for(int dz=-1;dz<=1;dz++){
var chunk=level.getChunk(cx+dx,cz+dz);
for(int qx=(cx+dx)*4;qx<(cx+dx)*4+4;qx++)for(int qz=(cz+dz)*4;qz<(cz+dz)*4+4;qz++){
int top=(int)f.column(qx*4,qz*4).top();if(top<0)continue;
for(int qy=(top-20)>>2;qy<=top/4+2;qy++){
String expected=f.biome(qx*4,qy*4,qz*4);
String actual=chunk.getNoiseBiome(qx,qy,qz).getRegisteredName();
checked++;if(!actual.equals(expected))mismatches++;
}
}
}
}
result.put("storedBiomes",Map.of("checked",checked,"mismatches",mismatches));
require(mismatches==0,"Stored chunk biomes disagree with global ecology: "+mismatches+"/"+checked);
}
private static void require(boolean condition,String message){if(!condition)throw new AssertionError(message);}
}
@@ -0,0 +1,123 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Blocks;
/** Native checks of the unwarped noise volume and retained northern ecology, on new development worlds. */
final class North206Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain206.field(island);
double lo=999,hi=0,thickness=0;var covers=new EnumMap<NorthTerrain206.Surface,Integer>(NorthTerrain206.Surface.class);
BlockPos cave=null,fault=null;double deepest=-1,bestFault=-1;
var original=new NorthTerrain205.Field(island,f.shelf.original);long oldRock=0,newRock=0;int surfaceChanged=0;
for(int dx=-384;dx<=384;dx+=24)for(int dz=-384;dz<=384;dz+=24){
int x=island.centerX()+dx,z=island.centerZ()+dz;var c=f.column(x,z);if(c.top()<0||c.edge()<80)continue;
if(c.top()!=original.column(x,z).top())surfaceChanged++;
for(int y=4;y<316;y+=4){if(original.density(x,y,z)>0)oldRock++;if(f.density(x,y,z)>0)newRock++;}
int lining=0;for(int y=(int)c.bottom()+8;y<c.top()-24;y++)if(f.fault(x,y,z)>=0&&f.fault(x,y,z)<1.8&&f.density(x,y,z)>0)lining++;
if(lining>bestFault){bestFault=lining;fault=new BlockPos(x,(int)c.top()-32,z);}
lo=Math.min(lo,c.top());hi=Math.max(hi,c.top());thickness=Math.max(thickness,c.top()-c.bottom());
var cover=f.cover(x,z);covers.merge(cover.surface(),1,Integer::sum);
// Raw 3D noise does not guarantee a cave in the thickest mountain column.
// Locate a genuinely empty covered pocket, then verify its blocks in native chunks.
int open=0;for(int y=cover.caveLow()+4;y<cover.caveHigh()-4;y+=4)if(f.density(x,y,z)<-.05)open++;
double room=cover.caveHigh()-cover.caveLow();double score=open*100+room*.01;
if(open>2&&room>12&&score>deepest){deepest=score;cave=new BlockPos(x,(int)c.top(),z);}
}
require(hi-lo>60&&thickness<110,"Roof relief or shelf thickness wrong: "+lo+".."+hi+", thickness="+thickness);
require(surfaceChanged==0,"Roof changed in "+surfaceChanged+" columns");
require(newRock<oldRock*.8,"Too much underground mass retained: "+newRock+"/"+oldRock);
result.put("massComparison",Map.of("oldRockSamples",oldRock,"newRockSamples",newRock,"changedSurfaceColumns",surfaceChanged));
result.put("noiseRelief",Map.of("minTop",lo,"maxTop",hi,"maxThickness",thickness,"surfaces",covers));
require(fault!=null&&bestFault>0,"No amethyst seam in density");
BlockPos entrance=null;
int amethyst=0,calcite=0,basalt=0,crystals=0,openAmethyst=0;
for(int dx=-24;dx<=24;dx++)for(int dz=-24;dz<=24;dz++){
int x=fault.getX()+dx,z=fault.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);
for(int y=Math.max(1,(int)c.bottom());y<c.top()-20;y++){
var pos=new BlockPos(x,y,z);var b=chunk.getBlockState(pos);
if(b.is(Blocks.AMETHYST_BLOCK)||b.is(Blocks.BUDDING_AMETHYST)){
amethyst++;
for(var dir:net.minecraft.core.Direction.values())if(level.getBlockState(pos.relative(dir)).isAir()){openAmethyst++;if(entrance==null&&level.getBlockState(pos.relative(dir).above()).isAir())entrance=pos.relative(dir);break;}
}
if(b.is(Blocks.CALCITE))calcite++;if(b.is(Blocks.SMOOTH_BASALT))basalt++;
if(b.getBlock() instanceof net.minecraft.world.level.block.AmethystClusterBlock)crystals++;
}
}
require(amethyst>50&&calcite>50&&basalt>50&&openAmethyst>10&&crystals>5,"Open amethyst fault absent: "+amethyst+"/"+openAmethyst+"/"+crystals);
result.put("amethystFault",Map.of("centre",fault.toShortString(),"entrance",entrance==null?fault.toShortString():entrance.toShortString(),"amethyst",amethyst,"calcite",calcite,"basalt",basalt,"crystals",crystals,"openFaces",openAmethyst));
int nativeWater=0;BlockPos poolSite=null;
var checkedPools=new HashSet<BlockPos>();
outer:for(int dx=-256;dx<=256;dx+=64)for(int dz=-256;dz<=256;dz+=64){
var pools=f.poolsNear(level,island.centerX()+dx,island.centerZ()+dz);
for(var p:pools){
if(!checkedPools.add(p))continue;
level.getChunkAt(p);if(!level.getBlockState(p).is(Blocks.WATER))continue;
require(level.getBlockState(p.below()).isSolidRender(),"Pool has no floor: "+p);
for(var n:List.of(p.north(),p.south(),p.east(),p.west()))require(level.getBlockState(n).isSolidRender()||level.getBlockState(n).is(Blocks.WATER),"Pool leaks: "+n);
nativeWater++;poolSite=p;
}
if(nativeWater>=6)break outer;
}
require(nativeWater>=6,"No sealed shallow wet cavity; planned="+checkedPools.size());
result.put("wetCavity",Map.of("water",nativeWater,"site",poolSite.toShortString()));
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("NORTH206_CAVITIES mass={} fault={} water={}",result.get("massComparison"),result.get("amethystFault"),result.get("wetCavity"));
var wood=f.sample(NorthTerrain206.Surface.OLD_GROWTH);int logs=0,leaves=0,tallest=0,podzol=0;
for(int dx=-32;dx<=32;dx++)for(int dz=-32;dz<=32;dz++){
int x=wood.getX()+dx,z=wood.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);int trunk=0;
for(int y=Math.max(1,(int)c.top()-20);y<=c.top()+80;y++){
var b=chunk.getBlockState(new BlockPos(x,y,z));
if(b.is(Blocks.SPRUCE_LOG)){logs++;trunk++;}if(b.is(Blocks.SPRUCE_LEAVES))leaves++;if(b.is(Blocks.PODZOL))podzol++;
}
tallest=Math.max(tallest,trunk);
}
require(tallest>=40&&logs>100&&leaves>100&&podzol>50,"Giant taiga absent: "+tallest+" / "+logs+" / "+podzol);
result.put("nativeGiantTaiga",Map.of("centre",wood.toShortString(),"tallestTrunk",tallest,"logs",logs,"leaves",leaves,"podzol",podzol));
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("NORTH206_GEOGRAPHY {} / {}",result.get("noiseRelief"),result.get("nativeGiantTaiga"));
int ice=0,air=0;
require(cave!=null&&deepest>20,"No covered cave volume");
for(int dx=-24;dx<=24;dx+=4)for(int dz=-24;dz<=24;dz+=4){
int x=cave.getX()+dx,z=cave.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.cover(x,z);
for(int y=c.caveLow();y<=c.caveHigh();y++){
var b=chunk.getBlockState(new BlockPos(x,y,z));if(b.is(Blocks.PACKED_ICE)||b.is(Blocks.BLUE_ICE))ice++;if(b.isAir())air++;
}
}
require(ice>20&&air>30,"Native ice cavern absent: "+ice+" / "+air);
result.put("iceCavern",Map.of("peak",cave.toShortString(),"ice",ice,"air",air));
var peaks=f.sample(NorthTerrain206.Surface.GLACIER);var materials=new HashMap<String,Integer>();
for(int dx=-24;dx<=24;dx+=2)for(int dz=-24;dz<=24;dz+=2){
int x=peaks.getX()+dx,z=peaks.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);
int y=chunk.getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.OCEAN_FLOOR,x&15,z&15);
for(int k=y-6;k<=y;k++){
var b=chunk.getBlockState(new BlockPos(x,k,z)).getBlock();materials.merge(net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(b).toString(),1,Integer::sum);
}
}
result.put("glacier",Map.of("centre",peaks.toShortString(),"materials",materials));
// The lower, unwarped relief also uses normal ice; a glacier need not be blue ice.
int glacierIce=materials.getOrDefault("minecraft:ice",0)+materials.getOrDefault("minecraft:packed_ice",0)+materials.getOrDefault("minecraft:blue_ice",0);
require(glacierIce>50,"No native glacier ice: "+materials);
// Compare stored biome cells on both sides of real chunk edges with the same world field.
// A resolver snapshot or request-order error must not leave one chunk on a different palette.
int checked=0,mismatches=0;
for(var centre:List.of(wood,peaks,village.arrival())){
int cx=centre.getX()>>4,cz=centre.getZ()>>4;
for(int dx=-1;dx<=1;dx++)for(int dz=-1;dz<=1;dz++){
var chunk=level.getChunk(cx+dx,cz+dz);
for(int qx=(cx+dx)*4;qx<(cx+dx)*4+4;qx++)for(int qz=(cz+dz)*4;qz<(cz+dz)*4+4;qz++){
int top=(int)f.column(qx*4,qz*4).top();if(top<0)continue;
for(int qy=(top-20)>>2;qy<=top/4+2;qy++){
String expected=f.biome(qx*4,qy*4,qz*4);
String actual=chunk.getNoiseBiome(qx,qy,qz).getRegisteredName();
checked++;if(!actual.equals(expected))mismatches++;
}
}
}
}
result.put("storedBiomes",Map.of("checked",checked,"mismatches",mismatches));
require(mismatches==0,"Stored chunk biomes disagree with global ecology: "+mismatches+"/"+checked);
}
private static void require(boolean condition,String message){if(!condition)throw new AssertionError(message);}
}
@@ -0,0 +1,98 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.levelgen.densityfunction.SamplerContext;
/** Fresh-world checks of the new landscape and a complete, furnished native mansion. */
final class North207Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain207.field(island);var context=SamplerContext.builder().build();
int raised=0,unchanged=0,deep=0;double highest=0;BlockPos summit=null,fault=null;int liningBest=0;
for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){
int x=island.centerX()+dx,z=island.centerZ()+dz;var c=f.column(x,z);if(c.top()<0||c.edge()<64)continue;
var old=f.shelf.column(context,x,z);double lift=c.top()-old.top();
if(lift>2)raised++;else unchanged++;
if(lift>highest){highest=lift;summit=new BlockPos(x,(int)c.top()+2,z);}
for(int y=8;y<old.top()-8;y+=8){require(f.density(x,y,z)==f.shelf.sampleValue(context,x,y,z),"Deep density changed");deep++;}
int lining=0;for(int y=(int)c.bottom()+8;y<old.top()-24;y++)if(f.fault(x,y,z)>=0&&f.fault(x,y,z)<1.8&&f.density(x,y,z)>0)lining++;
if(lining>liningBest){liningBest=lining;fault=new BlockPos(x,old.top()-32,z);}
}
require(raised>20&&unchanged>raised*2&&highest>24&&highest<60,"Missing or excessive local relief: "+raised+"/"+unchanged+"/"+highest);
result.put("crowns",Map.of("count",f.relief.crowns.size(),"raisedColumns",raised,"unchangedColumns",unchanged,"maxAddedHeight",highest,"deepSamplesUnchanged",deep,"summit",summit.toShortString()));
int amethyst=0,open=0;
require(fault!=null,"No amethyst field");
for(int dx=-16;dx<=16;dx++)for(int dz=-16;dz<=16;dz++){
int x=fault.getX()+dx,z=fault.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);
for(int y=(int)c.bottom();y<f.shelf.column(context,x,z).top()-20;y++){
var p=new BlockPos(x,y,z);var b=chunk.getBlockState(p);
if(b.is(Blocks.AMETHYST_BLOCK)||b.is(Blocks.BUDDING_AMETHYST)){
amethyst++;for(var d:net.minecraft.core.Direction.values())if(level.getBlockState(p.relative(d)).isAir()){open++;break;}
}
}
}
require(amethyst>100&&open>30,"Accepted open amethyst lost");result.put("amethyst",Map.of("site",fault.toShortString(),"blocks",amethyst,"openFaces",open));
var snowSite=forest(f,island,true);var drySite=forest(f,island,false);
result.put("snowyForest",checkForest(level,f,snowSite,true));result.put("dryForest",checkForest(level,f,drySite,false));
var mansion=NorthMansion207.cached(island);require(mansion!=null,"No supported mansion");var box=mansion.bounds();
for(int x=box.minX()>>4;x<=box.maxX()>>4;x++)for(int z=box.minZ()>>4;z<=box.maxZ()>>4;z++)level.getChunk(x,z);
int spruce=0,calcite=0,tuff=0,stairs=0,chests=0,loot=0,oldWood=0,leaves=0;
for(int x=box.minX();x<=box.maxX();x++)for(int z=box.minZ();z<=box.maxZ();z++)for(int y=box.minY();y<=box.maxY();y++){
var p=new BlockPos(x,y,z);var b=level.getBlockState(p);
if(b.is(Blocks.SPRUCE_PLANKS)||b.is(Blocks.STRIPPED_SPRUCE_LOG))spruce++;
if(b.is(Blocks.CALCITE))calcite++;if(b.is(Blocks.TUFF_BRICKS))tuff++;
if(b.is(Blocks.SPRUCE_STAIRS))stairs++;if(b.is(Blocks.CHEST))chests++;
if(b.is(Blocks.CHEST)&&level.getBlockEntity(p) instanceof net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity chest&&chest.getLootTable()!=null)loot++;
if(b.is(Blocks.DARK_OAK_PLANKS)||b.is(Blocks.OAK_PLANKS))oldWood++;
// Native decorative oak leaves are allowed; invading spruce canopies are not.
if(b.is(Blocks.SPRUCE_LEAVES))leaves++;
}
require(spruce>1000&&calcite>200&&tuff>100&&stairs>100&&chests>0&&oldWood==0,"Mansion absent or palette failed: "+spruce+"/"+calcite+"/"+stairs+"/"+chests+" old="+oldWood);
require(mansion.maxFoundationDepth()<=20,"Unsupported mansion");
require(loot>0,"No native mansion loot table");
for(var at:mansion.approach()){
require(level.getBlockState(at).is(Blocks.TUFF_BRICK_STAIRS)&&level.getBlockState(at.below()).isSolidRender(),"Unsupported entrance stair");
require(level.getBlockState(at.above()).isAir()&&level.getBlockState(at.above(2)).isAir(),"Blocked entrance approach");
}
result.put("mansion",Map.of("origin",mansion.origin().toShortString(),"bounds",box.toString(),"pieces",mansion.pieces().size(),"maxFoundationDepth",mansion.maxFoundationDepth(),"spruce",spruce,"calcite",calcite,"tuff",tuff,"stairs",stairs,"chests",chests,"spruceLeavesInBox",leaves));
result.put("mansionAccess",Map.of("stairs",mansion.approach().size(),"nativeLootChests",loot));
int checked=0,mismatches=0;
for(var site:List.of(snowSite,drySite,summit))for(int x=site.getX()-16;x<=site.getX()+16;x+=4)for(int z=site.getZ()-16;z<=site.getZ()+16;z+=4){
int qx=x>>2,qz=z>>2,top=(int)f.column(qx*4,qz*4).top();var chunk=level.getChunk(x>>4,z>>4);
for(int qy=(top-20)>>2;qy<=(top+8)>>2;qy++){checked++;if(!chunk.getNoiseBiome(qx,qy,qz).getRegisteredName().equals(f.biome(qx*4,qy*4,qz*4)))mismatches++;}
}
require(mismatches==0,"Stored ecology mismatch");result.put("storedBiomes",Map.of("checked",checked,"mismatches",mismatches));
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("NORTH207_VERIFIED crowns={} snowy={} dry={} mansion={}",result.get("crowns"),result.get("snowyForest"),result.get("dryForest"),result.get("mansion"));
}
private static BlockPos forest(NorthTerrain207.Field f,ExpansionIsland i,boolean snow){
BlockPos best=null;int bestScore=-1;
for(int dx=-320;dx<=320;dx+=16)for(int dz=-320;dz<=320;dz+=16){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()<80||NorthMansion207.reserved(i,x,z))continue;
int score=0;
for(int a=-24;a<=24;a+=8)for(int b=-24;b<=24;b+=8){var cover=f.cover(x+a,z+b).surface();if((cover==NorthTerrain207.Surface.OLD_GROWTH||cover==NorthTerrain207.Surface.TAIGA)&&f.forestSnow(x+a,z+b)==snow)score++;}
if(score>bestScore){bestScore=score;best=new BlockPos(x,(int)c.top()+2,z);}
}
require(bestScore>30,"Missing coherent forest patch "+snow);return best;
}
private static Map<String,Object> checkForest(ServerLevel level,NorthTerrain207.Field f,BlockPos centre,boolean snowy){
int eligible=0,snow=0,dry=0,logs=0,leaves=0;
for(int dx=-24;dx<=24;dx++)for(int dz=-24;dz<=24;dz++){
int x=centre.getX()+dx,z=centre.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);var kind=f.cover(x,z).surface();
boolean forest=kind==NorthTerrain207.Surface.OLD_GROWTH||kind==NorthTerrain207.Surface.TAIGA;
for(int y=(int)c.top()-12;y<c.top()+80;y++){
var p=new BlockPos(x,y,z);var b=chunk.getBlockState(p);
if(b.is(Blocks.SPRUCE_LOG))logs++;if(b.is(Blocks.SPRUCE_LEAVES))leaves++;
if(forest&&f.forestSnow(x,z)==snowy&&(b.is(Blocks.GRASS_BLOCK)||b.is(Blocks.PODZOL))){
var above=chunk.getBlockState(p.above());eligible++;if(above.is(Blocks.SNOW)){snow++;require(b.getValue(net.minecraft.world.level.block.state.properties.BlockStateProperties.SNOWY),"Snowy soil flag absent");}else if(!above.is(Blocks.SPRUCE_LOG))dry++;
}
}
}
require(logs>20&&leaves>100,"Forest missing around "+centre);
require(snowy?snow>100:dry>100&&snow==0,"Snow mix missing: "+snow+"/"+dry);
return Map.of("site",centre.toShortString(),"eligible",eligible,"snow",snow,"dry",dry,"logs",logs,"leaves",leaves);
}
private static void require(boolean yes,String message){if(!yes)throw new AssertionError(message);}
}
@@ -0,0 +1,129 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.levelgen.densityfunction.SamplerContext;
/** Fresh-world checks of the new landscape and a complete, furnished native mansion. */
final class North208Checks {
static void verify(ServerLevel level,ExpansionIsland island,NorthVillage200.Plan village,Map<String,Object> result){
var f=NorthTerrain208.field(island);var context=SamplerContext.builder().build();
int raised=0,unchanged=0,deep=0;double highest=0;BlockPos summit=null,fault=null;int liningBest=0;
for(int dx=-384;dx<=384;dx+=16)for(int dz=-384;dz<=384;dz+=16){
int x=island.centerX()+dx,z=island.centerZ()+dz;var c=f.column(x,z);if(c.top()<0||c.edge()<64)continue;
var old=f.shelf.column(context,x,z);double lift=c.top()-old.top();
if(lift>2)raised++;else unchanged++;
if(lift>highest){highest=lift;summit=new BlockPos(x,(int)c.top()+2,z);}
for(int y=8;y<old.top()-8;y+=8){require(f.density(x,y,z)==f.shelf.sampleValue(context,x,y,z),"Deep density changed");deep++;}
int lining=0;for(int y=(int)c.bottom()+8;y<old.top()-24;y++)if(f.fault(x,y,z)>=0&&f.fault(x,y,z)<1.8&&f.density(x,y,z)>0)lining++;
if(lining>liningBest){liningBest=lining;fault=new BlockPos(x,old.top()-32,z);}
}
require(raised>20&&unchanged>raised*2&&highest>24&&highest<60,"Missing or excessive local relief: "+raised+"/"+unchanged+"/"+highest+" at "+summit);
result.put("crowns",Map.of("count",f.relief.crowns.size(),"raisedColumns",raised,"unchangedColumns",unchanged,"maxAddedHeight",highest,"deepSamplesUnchanged",deep,"summit",summit.toShortString()));
int pointed=0;var peakDrops=new ArrayList<Double>();
for(var crown:f.relief.crowns){
int px=crown.x(),pz=crown.z();double top=-1;
for(int x=crown.x()-6;x<=crown.x()+6;x++)for(int z=crown.z()-6;z<=crown.z()+6;z++)if(f.relief.top(x,z)>top){top=f.relief.top(x,z);px=x;pz=z;}
double fall=0;
for(int n=0;n<8;n++){double a=n*Math.PI/4;fall+=top-f.relief.top(px+(int)Math.round(8*Math.cos(a)),pz+(int)Math.round(8*Math.sin(a)));}
peakDrops.add(fall/8);if(fall/8>3)pointed++;
}
require(pointed>=3,"Native summits still rounded: "+peakDrops);result.put("summitDropsAt8Blocks",peakDrops);
int ice=0,solidBeds=0,formations=0;var sites=new ArrayList<Map<String,Object>>();
for(var t:f.relief.terraces){
int localIce=0;
for(int x=t.x()-6;x<=t.x()+6;x++)for(int z=t.z()-6;z<=t.z()+6;z++){
var p=f.relief.pocket(x,z);if(p==null)continue;
var chunk=level.getChunk(x>>4,z>>4);
for(int y=p.level()-4;y<=p.level()+2;y++){
var at=new BlockPos(x,y,z);var b=chunk.getBlockState(at);
if(b.is(Blocks.ICE)||b.is(Blocks.PACKED_ICE)||b.is(Blocks.BLUE_ICE)){
localIce++;ice++;if(level.getBlockState(at.below()).isSolidRender())solidBeds++;
}
}
}
sites.add(Map.of("x",t.x(),"y",t.level(),"z",t.z(),"iceBlocks",localIce));
}
for(var sp:f.relief.spires)for(int x=sp.x()-3;x<=sp.x()+3;x++)for(int z=sp.z()-3;z<=sp.z()+3;z++){
var chunk=level.getChunk(x>>4,z>>4);
for(int y=sp.base()+2;y<=sp.base()+sp.height();y++)if(chunk.getBlockState(new BlockPos(x,y,z)).is(Blocks.PACKED_ICE))formations++;
}
require(f.relief.terraces.size()>=2&&ice>40&&solidBeds>ice*.90,"Missing or unsupported glacial benches: "+ice+"/"+solidBeds);
require(formations>10,"Missing bank ice formations: "+formations);
result.put("glacialBenches",Map.of("sites",sites,"ice",ice,"supported",solidBeds,"formationIce",formations));
int amethyst=0,open=0;
require(fault!=null,"No amethyst field");
for(int dx=-16;dx<=16;dx++)for(int dz=-16;dz<=16;dz++){
int x=fault.getX()+dx,z=fault.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);
for(int y=(int)c.bottom();y<f.shelf.column(context,x,z).top()-20;y++){
var p=new BlockPos(x,y,z);var b=chunk.getBlockState(p);
if(b.is(Blocks.AMETHYST_BLOCK)||b.is(Blocks.BUDDING_AMETHYST)){
amethyst++;for(var d:net.minecraft.core.Direction.values())if(level.getBlockState(p.relative(d)).isAir()){open++;break;}
}
}
}
require(amethyst>100&&open>30,"Accepted open amethyst lost");result.put("amethyst",Map.of("site",fault.toShortString(),"blocks",amethyst,"openFaces",open));
var snowSite=forest(f,island,true);var drySite=forest(f,island,false);
result.put("snowyForest",checkForest(level,f,snowSite,true));result.put("dryForest",checkForest(level,f,drySite,false));
var mansion=NorthMansion208.cached(island);require(mansion!=null,"No supported mansion");var box=mansion.bounds();
for(int x=box.minX()>>4;x<=box.maxX()>>4;x++)for(int z=box.minZ()>>4;z<=box.maxZ()>>4;z++)level.getChunk(x,z);
int spruce=0,calcite=0,tuff=0,stairs=0,chests=0,loot=0,oldWood=0,leaves=0;
for(int x=box.minX();x<=box.maxX();x++)for(int z=box.minZ();z<=box.maxZ();z++)for(int y=box.minY();y<=box.maxY();y++){
var p=new BlockPos(x,y,z);var b=level.getBlockState(p);
if(b.is(Blocks.SPRUCE_PLANKS)||b.is(Blocks.STRIPPED_SPRUCE_LOG))spruce++;
if(b.is(Blocks.CALCITE))calcite++;if(b.is(Blocks.TUFF_BRICKS))tuff++;
if(b.is(Blocks.SPRUCE_STAIRS))stairs++;if(b.is(Blocks.CHEST))chests++;
if(b.is(Blocks.CHEST)&&level.getBlockEntity(p) instanceof net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity chest&&chest.getLootTable()!=null)loot++;
if(b.is(Blocks.DARK_OAK_PLANKS)||b.is(Blocks.OAK_PLANKS))oldWood++;
// Native decorative oak leaves are allowed; invading spruce canopies are not.
if(b.is(Blocks.SPRUCE_LEAVES))leaves++;
}
require(spruce>1000&&calcite>200&&tuff>100&&stairs>100&&chests>0&&oldWood==0,"Mansion absent or palette failed: "+spruce+"/"+calcite+"/"+stairs+"/"+chests+" old="+oldWood);
require(mansion.maxFoundationDepth()<=20,"Unsupported mansion");
require(loot>0,"No native mansion loot table");
for(var at:mansion.approach()){
require(level.getBlockState(at).is(Blocks.TUFF_BRICK_STAIRS)&&level.getBlockState(at.below()).isSolidRender(),"Unsupported entrance stair");
require(level.getBlockState(at.above()).isAir()&&level.getBlockState(at.above(2)).isAir(),"Blocked entrance approach");
}
result.put("mansion",Map.of("origin",mansion.origin().toShortString(),"bounds",box.toString(),"pieces",mansion.pieces().size(),"maxFoundationDepth",mansion.maxFoundationDepth(),"spruce",spruce,"calcite",calcite,"tuff",tuff,"stairs",stairs,"chests",chests,"spruceLeavesInBox",leaves));
result.put("mansionAccess",Map.of("stairs",mansion.approach().size(),"nativeLootChests",loot));
int checked=0,mismatches=0;
for(var site:List.of(snowSite,drySite,summit))for(int x=site.getX()-16;x<=site.getX()+16;x+=4)for(int z=site.getZ()-16;z<=site.getZ()+16;z+=4){
int qx=x>>2,qz=z>>2,top=(int)f.column(qx*4,qz*4).top();var chunk=level.getChunk(x>>4,z>>4);
for(int qy=(top-20)>>2;qy<=(top+8)>>2;qy++){checked++;if(!chunk.getNoiseBiome(qx,qy,qz).getRegisteredName().equals(f.biome(qx*4,qy*4,qz*4)))mismatches++;}
}
require(mismatches==0,"Stored ecology mismatch");result.put("storedBiomes",Map.of("checked",checked,"mismatches",mismatches));
fr.koka.sanctuary.SanctuaryMod.LOGGER.info("NORTH208_VERIFIED crowns={} snowy={} dry={} mansion={}",result.get("crowns"),result.get("snowyForest"),result.get("dryForest"),result.get("mansion"));
}
private static BlockPos forest(NorthTerrain208.Field f,ExpansionIsland i,boolean snow){
BlockPos best=null;int bestScore=-1;
for(int dx=-320;dx<=320;dx+=16)for(int dz=-320;dz<=320;dz+=16){
int x=i.centerX()+dx,z=i.centerZ()+dz;var c=f.column(x,z);if(c.edge()<80||NorthMansion208.reserved(i,x,z))continue;
int score=0;
for(int a=-24;a<=24;a+=8)for(int b=-24;b<=24;b+=8){var cover=f.cover(x+a,z+b).surface();if((cover==NorthTerrain208.Surface.OLD_GROWTH||cover==NorthTerrain208.Surface.TAIGA)&&f.forestSnow(x+a,z+b)==snow)score++;}
if(score>bestScore){bestScore=score;best=new BlockPos(x,(int)c.top()+2,z);}
}
require(bestScore>30,"Missing coherent forest patch "+snow);return best;
}
private static Map<String,Object> checkForest(ServerLevel level,NorthTerrain208.Field f,BlockPos centre,boolean snowy){
int eligible=0,snow=0,dry=0,logs=0,leaves=0;
for(int dx=-24;dx<=24;dx++)for(int dz=-24;dz<=24;dz++){
int x=centre.getX()+dx,z=centre.getZ()+dz;var chunk=level.getChunk(x>>4,z>>4);var c=f.column(x,z);var kind=f.cover(x,z).surface();
boolean forest=kind==NorthTerrain208.Surface.OLD_GROWTH||kind==NorthTerrain208.Surface.TAIGA;
for(int y=(int)c.top()-12;y<c.top()+80;y++){
var p=new BlockPos(x,y,z);var b=chunk.getBlockState(p);
if(b.is(Blocks.SPRUCE_LOG))logs++;if(b.is(Blocks.SPRUCE_LEAVES))leaves++;
if(forest&&f.forestSnow(x,z)==snowy&&(b.is(Blocks.GRASS_BLOCK)||b.is(Blocks.PODZOL))){
var above=chunk.getBlockState(p.above());eligible++;if(above.is(Blocks.SNOW)){snow++;require(b.getValue(net.minecraft.world.level.block.state.properties.BlockStateProperties.SNOWY),"Snowy soil flag absent");}else if(!above.is(Blocks.SPRUCE_LOG))dry++;
}
}
}
require(logs>20&&leaves>100,"Forest missing around "+centre);
require(snowy?snow>100:dry>100&&snow==0,"Snow mix missing: "+snow+"/"+dry);
return Map.of("site",centre.toShortString(),"eligible",eligible,"snow",snow,"dry",dry,"logs",logs,"leaves",leaves);
}
private static void require(boolean yes,String message){if(!yes)throw new AssertionError(message);}
}
@@ -0,0 +1,91 @@
package fr.koka.sanctuarytest;
import com.google.gson.*;
import fr.koka.sanctuary.SanctuaryMod;
import java.nio.file.*;
import java.util.*;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Screenshot;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.storage.LevelResource;
/** Opt-in native Vulkan screenshots in disposable photo worlds only; inactive during ordinary visits. */
final class PhotoVisit193 {
record Shot(String name,double x,double y,double z,float yaw,float pitch){}
private static List<Shot> shots;
private static int index=-1,ticks,settled;
private static boolean writing,finished,confirmed,identitySubmitted;
private static long arrived;
static void register(){
var path=System.getProperty("sanctuary.photo193");if(path==null)return;
try{
var values=JsonParser.parseString(Files.readString(Path.of(path))).getAsJsonArray();var list=new ArrayList<Shot>();
for(var v:values){var o=v.getAsJsonObject();var name=o.get("name").getAsString();
if(!name.matches("[a-z0-9_-]{1,64}"))throw new IllegalArgumentException("Invalid photograph name");
list.add(new Shot(name,o.get("x").getAsDouble(),o.get("y").getAsDouble(),o.get("z").getAsDouble(),o.get("yaw").getAsFloat(),o.get("pitch").getAsFloat()));
}
var run=Path.of(path).toAbsolutePath().normalize().getParent();
var world=JsonParser.parseString(Files.readString(run.resolve("solo.json"))).getAsJsonObject().get("world").getAsString();
if(!world.matches("Sanctuary-Photo-193-[0-9-]+"))throw new IllegalArgumentException("Wrong disposable photo world");
net.fabricmc.fabric.api.client.screen.v1.ScreenEvents.AFTER_INIT.register((mc,screen,w,h)->{
SanctuaryMod.LOGGER.info("PHOTO193_SCREEN {} {}",screen.getClass().getName(),screen.getTitle().getString());
if(!mc.gameDirectory.toPath().toAbsolutePath().normalize().equals(run.resolve("client")))throw new IllegalStateException("Photo client directory differs from its manifest");
if(!identitySubmitted&&screen instanceof fr.koka.sanctuary.client.HelloWorldScreen){
identitySubmitted=true;mc.execute(()->{
if(mc.gui.screen()!=screen)return;
var input=new net.minecraft.client.input.KeyEvent(257,0,0);
for(var suffix:List.of("$ColorButton","$StarterSlot"))for(var child:screen.children())
if(child instanceof net.minecraft.client.gui.components.Button b&&child.getClass().getName().endsWith(suffix)&&b.active){b.onPress(input);break;}
for(var child:screen.children())if(child instanceof net.minecraft.client.gui.components.EditBox box
&&box.getMessage().getString().equals(net.minecraft.network.chat.Component.translatable("sanctuary.starter.name").getString()))box.setValue("Labo");
for(var child:screen.children())if(child instanceof net.minecraft.client.gui.components.Button b&&b.active
&&b.getMessage().getString().equals(fr.koka.sanctuary.progression.ProgressionService.label("enter").getString())){b.onPress(input);break;}
});
}
// This warning is expected for our newly copied experimental preset. Never accept a general dialog.
if(!confirmed&&screen instanceof net.minecraft.client.gui.screens.BackupConfirmScreen
&&screen.getTitle().getString().equals(net.minecraft.network.chat.Component.translatable("selectWorld.backupQuestion.experimental").getString())){
for(var child:screen.children())if(child instanceof net.minecraft.client.gui.components.Button b
&&b.getMessage().getString().equals(net.minecraft.network.chat.Component.translatable("selectWorld.backupJoinSkipButton").getString())){
confirmed=true;mc.execute(()->{if(mc.gui.screen()==screen)b.onPress(new net.minecraft.client.input.KeyEvent(257,0,0));});break;
}
}
});
shots=List.copyOf(list);if(shots.isEmpty())throw new IllegalArgumentException("Empty visit");
}catch(Exception e){throw new IllegalStateException("Invalid photo visit",e);}
ClientTickEvents.END_CLIENT_TICK.register(PhotoVisit193::tick);
}
private static void tick(Minecraft mc){
if(finished||mc.level==null||mc.player==null||mc.getSingleplayerServer()==null)return;
var server=mc.getSingleplayerServer();
if(!server.getWorldPath(LevelResource.ROOT).toAbsolutePath().normalize().getFileName().toString().startsWith("Sanctuary-Photo-193-"))throw new IllegalStateException("Photographs require a disposable photo world");
if(!WorldgenLab.coherent193(server.overworld().getChunkSource().getGenerator()))throw new IllegalStateException("Wrong photograph generator");
if(!mc.gui.hud.isHidden())mc.gui.hud.toggle();mc.gui.setScreen(null);
if(writing)return;
if(index<0||ticks<0){
index++;ticks=0;settled=0;arrived=System.nanoTime();
if(index==shots.size()){
finished=true;SanctuaryMod.LOGGER.info("PHOTO193_FINISHED shots={}",index);mc.stop();return;
}
var shot=shots.get(index);var id=mc.player.getUUID();
server.execute(()->{var player=server.getPlayerList().getPlayer(id);if(player!=null){player.setGameMode(GameType.SPECTATOR);player.connection.teleport(shot.x,shot.y,shot.z,shot.yaw,shot.pitch);}});
SanctuaryMod.LOGGER.info("PHOTO193_CAMERA {} {} {} {} yaw={} pitch={}",shot.name,shot.x,shot.y,shot.z,shot.yaw,shot.pitch);
return;
}
ticks++;
var shot=shots.get(index);
if(mc.player.distanceToSqr(shot.x,shot.y,shot.z)>4)return;
if(mc.levelRenderer.hasRenderedAllSections())settled++;else settled=0;
double seconds=(System.nanoTime()-arrived)/1e9;
if(seconds>180){finished=true;SanctuaryMod.LOGGER.error("PHOTO193_FAILED render timeout {}",shot.name);mc.stop();return;}
mc.player.setYRot(shot.yaw);mc.player.setXRot(shot.pitch);
if(seconds<12||settled<20)return;
writing=true;
Screenshot.grab(mc.gameDirectory,shot.name+".png",mc.gameRenderer.mainRenderTarget(),1,message->mc.execute(()->{
var file=mc.gameDirectory.toPath().resolve("screenshots").resolve(shot.name+".png");
if(!Files.isRegularFile(file))throw new IllegalStateException("Screenshot failed: "+message.getString());
SanctuaryMod.LOGGER.info("PHOTO193_SAVED {} renderSettledTicks={}",file,settled);writing=false;ticks=-1;
}));
}
}
@@ -11,6 +11,9 @@ import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
public final class QuickTestClient implements ClientModInitializer {
private final Set<Screen> initialized=Collections.newSetFromMap(new WeakHashMap<>());
public void onInitializeClient(){
AscentView184.register();
PhotoVisit193.register();
LabVisit200.register();
ClientConfigurationNetworking.registerGlobalReceiver(QuickTestMod.Mode.TYPE,(payload,context)->
context.client().execute(()->IntroClient.setQuickTestIntro(payload.quick())));
ScreenEvents.AFTER_INIT.register((minecraft,screen,width,height)->{
@@ -19,7 +19,7 @@ public final class QuickTestMod implements ModInitializer {
DuoLab.register();
HordeLab.register();
PalaceLab.register();
WorldgenLab.register();
WorldgenDiagnostics.register();
PayloadTypeRegistry.clientboundConfiguration().register(Mode.TYPE,Mode.CODEC);
ServerConfigurationConnectionEvents.CONFIGURE.register((handler,server)->{
if(ServerConfigurationNetworking.canSend(handler,Mode.TYPE))
@@ -0,0 +1,108 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
/** Disposable-world activation, interrupted preparation and native regional structure checks. */
final class Relays215Checks {
private record Run(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh,boolean south,CompletableFuture<ExpansionIsland> request,ItemStack payment) {}
private static Run run;
static void register(){ServerTickEvents.END_SERVER_TICK.register(Relays215Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
boolean current=Boolean.getBoolean("sanctuary.worldgenLab.south216");
boolean south=current||Boolean.getBoolean("sanctuary.worldgenLab.south215");int sector=south?4:0;
require(adapter!=null&&adapter.rootGeneration()==(current?216:215),"Wrong profile");
var session=ExpansionRuntime.session(level);result.put("verificationScope",current?"south216":south?"south215":"north215");
if(fresh){
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==sector).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing source anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var wrong=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,wrong,()->true).isCompletedExceptionally()&&wrong.getCount()==64,"Wrong offer accepted");
var demand=AnchorOffers189.DEMANDS.get(sector);var payment=new ItemStack(demand.item(),demand.count()+1);var request=RelayOffers199.offer(level,pos,payment,()->true);
require(RelayOffers199.offer(level,pos,payment,()->true).isCompletedExceptionally(),"Duplicate search accepted");
result.put("anchor",pos.toShortString());run=new Run(server,output,result,started,true,south,request,payment);
}else{
require(session.islands().size()==2,"Reservation not restored");
run=new Run(server,output,result,started,false,south,CompletableFuture.completedFuture(session.islands().get(1)),ItemStack.EMPTY);
}
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server()!=server)return;
try{
require(System.nanoTime()-r.started()<java.util.concurrent.TimeUnit.MINUTES.toNanos(8),"Timeout");
if(!r.request().isDone())return;
var admitted=r.request().join();var level=server.overworld();var session=ExpansionRuntime.session(level);
require(RegionalRelay215.active(admitted)&&admitted.diameter()==1024,"Wrong region");
r.result().put("expansion",Map.of("id",admitted.id(),"x",admitted.centerX(),"z",admitted.centerZ(),"diameter",admitted.diameter(),"seed",admitted.seed()));
if(r.fresh()){
require(r.payment().getCount()==1,"Wrong charge");require(session.island(admitted.id()).status().equals("reserved"),"Expected interrupted preparation");
r.result().put("interruptedProgress",session.progress());finish(r);return;
}
var i=session.island(admitted.id());
if(!i.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());var p=RegionalRelay215.plan(i);
require(adapter.relay(i).equals(p.anchor()),"Offering still uses old ground marker");
require(adapter.preparationChunks(i).size()<=110,"Unbounded preparation");
var touched=new HashSet<Long>();int blocks=0;
for(var part:p.chunks().entrySet()){
var cp=net.minecraft.world.level.ChunkPos.unpack(part.getKey());var chunk=level.getChunk(cp.x(),cp.z());touched.add(part.getKey());
for(var e:part.getValue().entrySet()){
var actual=chunk.getBlockState(e.getKey());require(actual==e.getValue(),"Monument mismatch "+e.getKey()+": "+actual+" != "+e.getValue());blocks++;
}
}
for(var a:p.approach()){
require(level.getBlockState(a).is(Blocks.TUFF_BRICK_STAIRS)&&level.getBlockState(a.above()).isAir()&&level.getBlockState(a.above(2)).isAir(),"Blocked stairs");
for(int y=a.getY()-1;y>=RegionalRelay215.ground(i,a.getX(),a.getZ());y--)require(level.getBlockState(new BlockPos(a.getX(),y,a.getZ())).isSolidRender(),"Floating approach");
}
var failure=RelayOffers199.offer(level,p.anchor(),new ItemStack(Items.DIRT),()->true);
try{failure.join();throw new AssertionError("Wrong payment accepted");}catch(java.util.concurrent.CompletionException expected){require("required".equals(expected.getCause().getMessage()),"Raised relay is not recognized: "+expected);}
require(!SouthVillage214.active(i)&&SouthVillage214.cached(i)==null,"Village generated in 215");
RegionalRelay215.release(i);var rebuilt=RegionalRelay215.plan(i);require(p.chunks().equals(rebuilt.chunks()),"Rebuilt plan changed");
r.result().put("monument",Map.of("anchor",p.anchor().toShortString(),"base",p.origin().toShortString(),"chunks",touched.size(),"checkedBlocks",blocks,"foundation",p.maxFoundationDepth(),"approachSteps",p.approach().size(),"preparedChunks",adapter.preparationChunks(i).size()));
BlockPos camera=p.anchor().offset(22,11,r.south()?-24:24);
var visit=new LinkedHashMap<String,Object>();visit.put("relay",p.anchor().toShortString());visit.put("entrance",p.anchor().toShortString());visit.put("camera",camera.toShortString());
if(r.south()){
var t=SouthTemple213.cached(i);var f=SouthTerrain213.field(i);
// Seed 0's derived South has no sufficiently buried site in the retained 215 recipe.
// Keep the known seed-42 pyramid mandatory while exercising vegetation on that absence case.
require(t!=null||i.generation()==216&&level.getSeed()==0,"Missing widened pyramid");
if(t==null)r.result().put("temple",Map.of("present",false,"reason","no_buried_site"));
else {
int chests=0,tnt=0,enchanted=0,plates=0,torches=0;
for(var e:SouthTemple213.blueprint(i).entrySet()){
var at=t.at(e.getKey());var expected=e.getValue().is(Blocks.TERRACOTTA)?f.colour(at.getX(),at.getY(),at.getZ()):e.getValue().rotate(t.rotation());
require(level.getBlockState(at).getBlock()==expected.getBlock(),"Pyramid mismatch at "+at);
if(expected.is(Blocks.TNT))tnt++;
if(expected.is(Blocks.STONE_PRESSURE_PLATE))plates++;if(expected.is(Blocks.TORCH))torches++;
if(expected.is(Blocks.STONE_PRESSURE_PLATE))require(level.getBlockState(at.below(2)).is(Blocks.TNT)&&level.getBlockState(at.below()).isSolidRender(),"Disconnected trap");
}
for(var at:t.chests()){
require(level.getBlockEntity(at) instanceof net.minecraft.world.level.block.entity.ChestBlockEntity,"Missing chest");
var chest=(net.minecraft.world.level.block.entity.ChestBlockEntity)level.getBlockEntity(at);chest.unpackLootTable(null);chests++;
for(int slot=0;slot<chest.getContainerSize();slot++)if(chest.getItem(slot).isEnchanted())enchanted++;
}
require(chests==10&&tnt==SouthTemple213.blueprint(i).values().stream().filter(b->b.is(Blocks.TNT)).count()&&enchanted>=10,"Labyrinth loot/traps changed");
r.result().put("temple",Map.of("origin",t.origin().toShortString(),"rotation",t.rotation().name(),"width",31,"chests",chests,"tnt",tnt,"enchantedStacks",enchanted,"pressurePlates",plates,"torches",torches));
if(i.generation()==216)require(torches==0&&plates>=30,"Missing dark traps");
visit.put("temple",t.origin().toShortString());
}
if(i.generation()==216)South216Checks.verify(level,i,r.result(),visit);
visit.put("arrival",f.arrival().toShortString());
}else visit.put("arrival",adapter.village(i).arrival().toShortString());
r.result().put("visit",visit);finish(r);
}catch(Throwable e){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("RELAYS215_CHECK_FAILED",e);server.halt(false);}
}
private static void finish(Run r){run=null;r.result().put("readyForVisitMs",(System.nanoTime()-r.started())/1_000_000);WorldgenDiagnostics.writeReport(r.output(),r.result());}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}
@@ -1,64 +0,0 @@
package fr.koka.sanctuarytest;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.resources.Identifier;
import net.minecraft.util.Interval;
import net.minecraft.world.level.levelgen.densityfunction.*;
/** A local wooded summit; the deep island and the aerial field remain unchanged. */
public record ReliefEcology177(DensityFunction base) implements DensityFunction {
public static final MapCodec<ReliefEcology177> CODEC=RecordCodecBuilder.mapCodec(i->i.group(
DensityFunction.CODEC.fieldOf("base").forGetter(ReliefEcology177::base)
).apply(i,ReliefEcology177::new));
@Override public DensitySampler compileSampler(CompileContext context){
var baseField=(SkyFragments175.Field)DfRewriteRule.INLINE_REFERENCE.rewrite(base).compileSampler(context);
var random=context.createRandom(Identifier.fromNamespaceAndPath("sanctuary_test","relief_ecology_v1"));
int bestX=0,bestZ=0,bestY=-1;
for(int i=0;i<12;i++){
double angle=random.nextDouble()*Math.PI*2, distance=70+random.nextInt(90);
int x=(int)(Math.cos(angle)*distance),z=(int)(Math.sin(angle)*distance);
int y=top(baseField,x,z);
if(y>bestY){bestX=x;bestZ=z;bestY=y;}
}
return new Field(baseField,bestX,bestZ);
}
private static int top(DensitySampler field,int x,int z){
for(int y=316;y>=48;y-=4)if(field.sampleValue(SamplerContext.EMPTY_UNCACHED,x,y,z)>0){
for(int fine=y+3;fine>=y;fine--)if(field.sampleValue(SamplerContext.EMPTY_UNCACHED,x,fine,z)>0)return fine;
}
return -1;
}
public static final class Field implements DensitySampler {
private final SkyFragments175.Field base;
private final int peakX,peakZ;
// Quart columns are shared by all biome heights. Fixed island bounds limit this cache.
private final ConcurrentHashMap<Long,Integer> tops=new ConcurrentHashMap<>();
Field(SkyFragments175.Field base,int x,int z){this.base=base;peakX=x;peakZ=z;}
public SkyFragments175.Field base(){return base;}
public int peakX(){return peakX;}public int peakZ(){return peakZ;}
public int cachedColumns(){return tops.size();}
public int surface(int x,int z){
x=x>>2<<2;z=z>>2<<2;
if(Math.hypot(x,z)>398)return -1;
final int sx=x,sz=z;
return tops.computeIfAbsent(((long)x<<32)^(z&0xffffffffL),ignored->top(this,sx,sz));
}
@Override public float sampleValue(SamplerContext context,int x,int y,int z){
if(y<=216 || y>=320)return base.sampleValue(context,x,y,z);
double radius=((x-peakX)*(double)(x-peakX)+(z-peakZ)*(double)(z-peakZ))/(96*96.0);
if(radius>=1)return base.sampleValue(context,x,y,z);
double lift=34*(1-radius)*(1-radius);
double source=216+(y-216)/(1+lift/56);
int low=(int)Math.floor(source);double blend=source-low;
double density=base.sampleValue(context,x,low,z)*(1-blend)+base.sampleValue(context,x,low+1,z)*blend;
return (float)Math.min(density,(316-y)*.15);
}
@Override public void sampleVolume(SamplerContext c,DensityBuffer b,DensityVolume v){DensitySampler.sampleVolumeNaive(c,b,v,this);}
}
@Override public DensityFunction rewriteChildren(DfRewriteRule rule){return new ReliefEcology177(rule.rewrite(base));}
@Override public Interval range(){return Interval.of(-1,1);}
@Override public int domainAxes(){return ALL_AXES;}
@Override public MapCodec<ReliefEcology177> codec(){return CODEC;}
}
@@ -0,0 +1,93 @@
package fr.koka.sanctuarytest;
import fr.koka.sanctuary.expansion.*;
import fr.koka.sanctuary.palace.*;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.*;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.levelgen.Heightmap;
/** Actual South offering and restart on disposable worlds only, then bounded native terrain samples. */
final class South209Checks {
private record Run(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh,CompletableFuture<ExpansionIsland> request,ItemStack payment) {}
private static Run run;
static void register(){ServerTickEvents.END_SERVER_TICK.register(South209Checks::tick);}
static void begin(MinecraftServer server,Path output,Map<String,Object> result,long started,boolean fresh){
var level=server.overworld();var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());
require(adapter!=null&&adapter.rootGeneration()==209,"Wrong profile");
var session=ExpansionRuntime.session(level);result.put("verificationScope","south209");
if(fresh){
var site=Anchors189.plan(Anchors189.source(level.getChunkSource().getGenerator()),level.getSeed()).sites().stream().filter(s->s.sector()==4).findFirst().orElseThrow();
var pos=site.anchor();level.getChunkAt(pos);level.getChunkAt(AnchorOffers189.CORE);
require(level.getBlockState(pos).is(ExpansionAnchorBlock.BLOCK),"Missing South anchor");
var core=level.getBlockState(AnchorOffers189.CORE);require(core.is(OriginBlock.BLOCK),"Missing core");
level.setBlock(AnchorOffers189.CORE,core.setValue(OriginBlock.LIT,true),Block.UPDATE_ALL);
var wrong=new ItemStack(Items.DIRT,64);require(RelayOffers199.offer(level,pos,wrong,()->true).isCompletedExceptionally()&&wrong.getCount()==64,"Wrong offer accepted");
var demand=AnchorOffers189.DEMANDS.get(4);var payment=new ItemStack(demand.item(),demand.count()+1);var request=RelayOffers199.offer(level,pos,payment,()->true);
require(RelayOffers199.offer(level,pos,payment,()->true).isCompletedExceptionally(),"Duplicate search accepted");
result.put("anchor",pos.toShortString());run=new Run(server,output,result,started,true,request,payment);
}else{
require(session.islands().size()==2,"Reservation not restored");
run=new Run(server,output,result,started,false,CompletableFuture.completedFuture(session.islands().get(1)),ItemStack.EMPTY);
}
}
private static void tick(MinecraftServer server){
var r=run;if(r==null||r.server()!=server)return;
try{
require(System.nanoTime()-r.started()<java.util.concurrent.TimeUnit.MINUTES.toNanos(8),"Timeout");
if(!r.request().isDone())return;
var admitted=r.request().join();var level=server.overworld();var session=ExpansionRuntime.session(level);
require(SouthTerrain209.active(admitted)&&admitted.diameter()==1024&&admitted.climate().equals("arid"),"Wrong region identity");
r.result().put("expansion",Map.of("id",admitted.id(),"x",admitted.centerX(),"z",admitted.centerZ(),"diameter",admitted.diameter()));
if(r.fresh()){
require(r.payment().getCount()==1,"Wrong charge");require(session.island(admitted.id()).status().equals("reserved"),"Expected interrupted preparation");
r.result().put("interruptedProgress",session.progress());finish(r);return;
}
var island=session.island(admitted.id());
if(!island.status().equals("ready")){require(!session.progress().contains("Exception")&&!session.progress().equals("idle"),"Preparation failed: "+session.progress());return;}
var adapter=LabExpansions199.get(level.getChunkSource().getGenerator());var f=SouthTerrain209.field(island);
require(adapter.preparationChunks(island).size()<=64,"Unbounded preparation");
var relay=f.relay();level.getChunkAt(relay);require(level.getBlockState(relay).is(ExpansionAnchorBlock.BLOCK)&&level.getBlockState(relay).getValue(ExpansionAnchorBlock.SECTOR)==4,"Missing South continuation");
for(int x=-1;x<=1;x++)for(int z=-1;z<=1;z++)for(int depth=1;depth<=7;depth++)
require(!level.getBlockState(relay.offset(x,-depth,z)).isAir(),"Relay footing hangs over air");
var markers=new ArrayList<BlockPos>();markers.add(f.arrival());markers.add(relay);
int valleys=0,mesas=0;double low=999,high=0;BlockPos canyon=null;double best=0;
for(int x=-320;x<=320;x+=16)for(int z=-320;z<=320;z+=16){
int wx=island.centerX()+x,wz=island.centerZ()+z;var c=f.shape.column(wx,wz);if(c.edge()<60)continue;
low=Math.min(low,c.top());high=Math.max(high,c.top());if(c.valley()>.9)valleys++;if(c.valley()<.1)mesas++;
double slope=Math.abs(c.top()-f.shape.column(wx+16,wz).top());
if(slope>best){best=slope;canyon=new BlockPos(wx,(int)c.top()+24,wz);}
}
require(valleys>80&&mesas>80&&high-low>95,"Missing mesas / valleys");markers.add(canyon);
for(int dx:new int[]{-192,0,192})markers.add(new BlockPos(island.centerX()+dx,210,island.centerZ()));
var colours=new HashSet<String>();int sand=0,blocks=0,unsupported=0,biomes=0;
for(var marker:markers){
for(int a=-8;a<=8;a+=4)for(int b=-8;b<=8;b+=4){
int x=marker.getX()+a,z=marker.getZ()+b;var chunk=level.getChunk(x>>4,z>>4);var c=f.shape.column(x,z);
int top=chunk.getHeight(Heightmap.Types.OCEAN_FLOOR,x&15,z&15);
require(Math.abs(top-f.top(x,z))<12,"Native surface diverges from density at "+x+","+z+": "+top+"/"+f.top(x,z));
require(level.getBiome(new BlockPos(x,top,z)).unwrapKey().orElseThrow().identifier().toString().equals("sanctuary:south_badlands209"),"Wrong chunk biome");biomes++;
for(int y=(int)c.bottom()-6;y<=top;y++){
var p=new BlockPos(x,y,z);var state=chunk.getBlockState(p);if(state.isAir())continue;blocks++;
var id=net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
if(id.endsWith("_terracotta"))colours.add(id);
if(state.getBlock() instanceof ConcretePowderBlock||state.is(Blocks.RED_SAND)){
sand++;if(chunk.getBlockState(p.below()).isAir())unsupported++;
}
}
}
}
require(colours.size()==16&&sand>10&&unsupported==0,"Palette/support: "+colours.size()+" colours, "+sand+" sand, "+unsupported+" unsupported");
r.result().put("terrain",Map.of("low",low,"high",high,"valleys",valleys,"mesas",mesas,"sampledBlocks",blocks,"colours",colours.size(),"sand",sand,"unsupportedPowder",unsupported,"biomeChecks",biomes));
r.result().put("visit",Map.of("arrival",f.arrival().toShortString(),"relay",relay.toShortString(),"canyon",canyon.toShortString()));
finish(r);
}catch(Throwable e){run=null;fr.koka.sanctuary.SanctuaryMod.LOGGER.error("SOUTH209_CHECK_FAILED",e);server.halt(false);}
}
private static void finish(Run r){run=null;r.result().put("readyForVisitMs",(System.nanoTime()-r.started())/1_000_000);WorldgenDiagnostics.writeReport(r.output(),r.result());}
private static void require(boolean value,String message){if(!value)throw new AssertionError(message);}
}

Some files were not shown because too many files have changed in this diff Show More