# Blocodex natif — connaissances, matière et stocks Ticket META-01, branche `codex/blocodex-natif`, cible Minecraft **26.3-pre-2**. Le Blocodex appartient au mod Sanctuary. Il est disponible sans appareil, recette ni déblocage. La mémoire personnelle, le recensement du terrain et celui des stocks forment un socle commun aux futures palettes de structures, règles d’expansion et règles du shop. Les relevés datés ajoutent la temporalité nécessaire à une future lecture de l’histoire économique du serveur. ## Contrat des informations La mémoire est personnelle : une identité de joueur (UUID), dans une sauvegarde de serveur, partagée entre ses dimensions. Les indicateurs sont indépendants. | Information | Sens | | --- | --- | | Inconnu | Aucune observation, possession, pose ni statistique de minage ou de jet. C'est un état calculé, pas une étape enregistrée. | | Vu | Le premier bloc rencontré par le regard du joueur, à au plus 32 blocs, observé côté serveur tous les 5 ticks. Les obstacles arrêtent le rayon ; les chunks absents ne sont pas chargés. Ce relevé ne couvre pas chaque pixel du champ de vision. | | Miné | Compteur vanilla `mined` du bloc. Ses règles sont conservées : notamment pas de minage créatif, ni de minage sans l'outil requis. | | Déjà possédé | Le bloc, sous forme d'item, a été présent dans l'inventaire personnel ou sur le curseur d'un menu. Les statistiques vanilla de ramassage et de jet prouvent aussi une possession passée. | | Jeté | Compteur vanilla `dropped` de l'item du bloc. Il compte les unités volontairement jetées, pas les objets éjectés à la mort ni le butin produit par le bloc cassé. | | Posé | Nombre de placements réussis par le joueur avec un item de bloc, y compris en créatif. Une tentative refusée, une interaction ou un placement par commande ne compte pas. | | En inventaire | Quantité actuellement dans l'inventaire personnel, équipement et curseur compris. Les coffres ouverts, ender chests et contenus imbriqués des boîtes ne sont pas inclus. | Les blocs sont identifiés par leur identifiant de registre ; les propriétés d'état (orientation, humidité, etc.) ne créent pas une nouvelle fiche. Deux identifiants restent distincts : une torche murale peut être vue et posée tandis que l'item possédé correspond à la torche debout. Les noms des blocs inconnus restent consultables, comme un catalogue ; cette version ne décide pas d'une politique de secrets ou de verrouillage des recettes. L'inventaire est observé chaque tick serveur, après les transactions de menus et avant la consommation d'un item placé. Les statistiques de ramassage/jet complètent ce relevé. Une mutation d'inventaire entièrement réalisée entre ces points par un autre mod ne peut pas être reconstruite après coup. Les spectateurs ne découvrent pas de blocs par le regard. ## Persistance et arrivée dans une sauvegarde antérieure Contrat additif v1 : fichiers `data/sanctuary-blocodex/.json`, enveloppe avec `schema: 1` et UUID, puis observations, possessions et poses par identifiant. Les statistiques vanilla restent dans leurs propres fichiers et sont seulement lues. Aucune conversion du terrain, des paramètres de génération, des chunks, du journal d'expansion ou des statistiques existantes n'est effectuée. Sans fichier Blocodex, les observations et poses commencent vides. Le minage, le jet et les preuves de possession sont disponibles depuis les statistiques vanilla déjà présentes. On n'invente pas les observations ni les poses passées à partir de `used`, qui compte aussi d'autres usages. Les changements sont sauvegardés tous les 600 ticks, lors de la sauvegarde du serveur, à la déconnexion et à l'arrêt. Un crash peut perdre les dernières observations ou poses non sauvegardées. Un fichier invalide ou d'une version inconnue désactive la mémoire concernée et n'est jamais remplacé silencieusement. Les identifiants de mods absents sont conservés sur disque. Les anciennes versions de Sanctuary ignorent ce répertoire additionnel ; les poses réalisées pendant un retour à une ancienne version ne peuvent pas être récupérées. ## Réutilisation `BlockKnowledgeService.knowledge(player, block)` et `snapshot(player)` renvoient des valeurs immuables calculées côté serveur. Le service expose aussi sa santé ; un consommateur doit refuser une condition de progression si la mémoire est indisponible, plutôt que d'interpréter une panne comme une découverte vierge. `BlockKnowledgeEvents.CHANGED` permet de réagir aux observations, possessions, poses et changements de statistiques. Les écouteurs s'exécutent sur le thread serveur ; ils ne constituent pas un journal transactionnel de récompenses. Cette livraison ne verrouille aucune recette et n'accorde aucune récompense. Palettes disponibles, recherches, progression et structures pourront ensuite définir leurs propres conditions en utilisant cette API commune. ### Palettes de structures `BlockKnowledgeService.palette(player, condition, tag)` croise les connaissances du joueur avec une famille de matériaux. Les critères `BlockKnowledgeFacet` sont combinables avec `and` et `or` : vus **ou** déjà possédés, minés **et** actuellement portés, etc. Le résultat immuable garde les identifiants triés et les quantités réellement portées. ```java var candidates = BlockKnowledgeService.palette(player, BlockKnowledgeFacet.SEEN.or(BlockKnowledgeFacet.POSSESSED), BlockKnowledgeService.NATURAL_STRUCTURE_MATERIALS); ``` Le tag `sanctuary:structure_palette/natural` fournit une première famille de pierres, terres, bois, feuilles et autres matériaux naturels, modifiable par datapack. D'autres tags pourront définir des palettes minérales, végétales ou propres à un biome. Le choix des couleurs, les contraintes physiques des blocs, les quantités nécessaires et la construction de la structure appartiendront au moteur de structures : une sélection de palette ne réserve aucun stock et ne place aucun bloc. ## Recensement du terrain chargé `TerrainCensus.snapshot(server)` expose une distribution des blocs par dimension ; `TerrainCensus.chunkSnapshot(level, pos)` fournit le détail d’un chunk déjà chargé. Ces lectures se font sur le thread serveur et renvoient des valeurs immuables. Elles parcourent les chunks `FULL` déjà accessibles, sans charger de chunk absent ni attendre la fin d’une génération. Le comptage utilise les palettes des sections de 16 × 16 × 16 blocs. Il regroupe les orientations et autres propriétés sous l’identifiant du bloc. Les blocs d’air sont exclus ; l’eau et la lave conservent leurs identifiants de blocs. Le budget est de **16 sections non vides par tick serveur**, partagé entre les dimensions et les demandes du même tick. Une section entièrement vide est reconnue par ses métadonnées, sans parcourir sa palette. Le relevé est progressif. Une section modifiée est retirée des totaux dès que sa révision change, puis remise dans la file de comptage. Les sections et chunks déchargés sortent du relevé. Un consommateur dispose, par dimension ou chunk, du nombre de sections chargées et comptées, du tick de capture, du tick du dernier comptage effectué et de l’âge de la plus ancienne attente. `complete()` et `coverage()` décrivent la couverture **des zones chargées**. Une couverture de 100 % ne signifie jamais que toute la sauvegarde a été lue. Pendant un rattrapage, zéro bloc compté ne prouve donc pas l’absence de ce bloc. Les futures règles d’expansion devront fixer leur couverture minimale et leur zone d’étude avant de prendre une décision. Les résultats en mémoire sont reconstruits après redémarrage ; ce service n’écrit pas dans les chunks et ne modifie pas leur génération. ## Recensement des stocks présents `StockCensus.snapshot(server)` photographie les objets accessibles au tick de la demande, sur le thread serveur. Le parcours des slots et des entités chargées est effectué à la demande ; aucun abonnement ne le relance à chaque tick. Les quantités sont des unités d’items, tous types confondus : un lingot, un outil ou une graine sont comptés même s’ils ne correspondent pas à un bloc. Les composants, l’usure et les enchantements ne créent pas de nouveaux identifiants de stock dans cette version. | Catégorie | Couverture | | --- | --- | | `playerItems` | Joueurs connectés : inventaire personnel, équipement et curseur du menu. Le contenu du menu ouvert n’est pas additionné. | | `blockContainerItems` | Entités de blocs déjà instanciées dans les chunks chargés, qui exposent l’interface `Container` : coffres, hoppers, fours, pots décorés, etc. Chaque moitié d’un double coffre est comptée une fois. | | `entityContainerItems` | Entités chargées qui exposent `Container`, notamment les wagonnets et bateaux à coffre. | | `groundItems` | Quantités des `ItemEntity` chargées et encore présentes au sol. | Le relevé ne déballe **aucune table de butin**. Tout conteneur dont la table reste à résoudre est ignoré avant la lecture de ses slots ; son existence augmente `pendingLootContainers`. Les entités de blocs encore stockées sous forme de NBT et non instanciées sont également laissées intactes, avec leur nombre dans `pendingBlockEntities`. Leur contenu n’est pas remplacé par une estimation. La couverture exclut les joueurs hors ligne, les chunks et entités déchargés, les ender chests, le contenu imbriqué des shulker boxes et bundles, les grilles de fabrication en cours dans l’inventaire ou l’établi (`menuInputsIncluded()` est faux), les inventaires et équipements des créatures. Le résultat de fabrication affiché avant validation ne constitue pas un stock supplémentaire. Elle exclut aussi les objets internes des entités de blocs qui n’exposent pas `Container`, comme les aliments d’un feu de camp ou le livre d’un pupitre. Une shulker box portée compte comme un item ; une shulker box posée et chargée expose son conteneur. Les exclusions figurent dans le contrat de couverture ; `partial()` reste vrai. Ce relevé indique où se trouvent les unités observées. Il ne les réserve pas, ne les transfère pas et n’évalue pas leur prix. Ajouter le terrain aux stocks ne donne pas une quantité immédiatement vendable : une roche dans un chunk reste différente d’un item dans un coffre. ## Consultation et futurs consommateurs communs `WorldCensusService.capture(server)` rassemble les deux relevés pour une même lecture côté serveur. Le consommateur réutilise cet instantané pendant son calcul et conserve ses informations de couverture. Le shop et les expansions pourront ainsi consulter la même base, avec leurs propres règles de fraîcheur, de portée géographique, de prix, de consommation et de réservation. Les diagnostics suivants sont réservés aux opérateurs : ```text /sanctuary census /sanctuary census block minecraft:stone /sanctuary census item minecraft:gold_ingot ``` Le résumé présente la couverture du terrain par dimension, les quatre catégories de stocks et les conteneurs au butin encore indéterminé. Le Blocodex personnel accessible par **B** conserve les données du joueur ; ces diagnostics ne diffusent pas les inventaires agrégés aux autres joueurs. ## Relevés datés — portée de l’alpha.23 La collecte regroupe les activités observées par **jour civil UTC**, pour l’ensemble du serveur, sans attribution à un UUID ou à une dimension : | Action | Registre et unité | | --- | --- | | `mined` | `block` : nombre de blocs minés, selon les règles des statistiques vanilla. | | `placed` | `block` : placements réussis par le joueur, créatif inclus et spectateurs exclus. | | `picked_up` | `item` : unités ramassées observées par les statistiques vanilla. | | `dropped` | `item` : unités volontairement jetées observées par les statistiques vanilla. | | `crafted` | `item` : unités fabriquées créditées au joueur par les statistiques vanilla. | Chaque combinaison conserve son action, son registre, son identifiant et une quantité entière sur 64 bits, saturée à la valeur maximale en cas de dépassement. Un compteur de minage n’est pas transformé en nombre d’items produits. Les actions antérieures à l’installation ne sont pas réparties artificiellement entre des dates à partir des statistiques cumulées de Minecraft. `MaterialActivityHistory.snapshot(server, day)` expose un instantané immuable avec le jour, les compteurs, `recorded` et `unsaved`. Un jour sans données enregistrées demeure inconnu ; il ne constitue pas un historique d’activité nulle. Les opérateurs peuvent consulter `/sanctuary history` ou préciser une date avec `/sanctuary history 2026-09-10`. La commande affiche au plus les 16 lignes aux quantités les plus élevées et indique combien ont été omises ; l’API conserve l’ensemble des compteurs du jour. La persistance additionnelle utilise `data/sanctuary-activity/YYYY-MM-DD.json`, avec un schéma 1 et des dates UTC. Elle est séparée de la mémoire personnelle et des chunks. Les écritures ont lieu tous les **600 ticks**, à la sauvegarde et à l’arrêt du serveur, ainsi qu’au changement de jour observé par le service. Un crash peut perdre les derniers relevés non sauvegardés, soit normalement jusqu’à 30 secondes de jeu à 20 ticks par seconde. Le fichier conserve les identifiants de mods absents ; il refuse les schémas inconnus, doublons, compteurs invalides et changements externes. Une erreur arrête la collecte et rend le service indisponible jusqu’à réparation puis redémarrage, en conservant le fichier en cause. Les limites sont de 100 000 tuples et 16 Mio par jour. Ces relevés permettent de distinguer des périodes d’activité. Ils ne conservent pas d’historique des instantanés de stocks, ne couvrent pas la fabrication automatique des machines et n’établissent ni consommation, ni perte, ni destination des objets. Ils ne retracent pas chaque transfert entre coffres ou chaque changement de propriétaire, et ne constituent pas un journal transactionnel d’achats, de récompenses ou de réservations. Le **ballast**, ses unités, ses conversions et sa traduction en géologie restent à concevoir dans le [cahier de cosmologie](cosmologie.md). Aucun objet n’est consommé et aucune Backroom n’est générée par ces mesures. ## Référence WSMC retrouvée La recherche locale a retrouvé une partie du travail précédent dans `/Users/koka/Documents/sanctuary/Gameplay/blocodex` : `ClientVoxelProjectBuilder` convertit des apparences de blocs et d’items en volumes/couches de blocs ; `BlocodexStudioPalettes` sélectionne des matériaux opaques appris. Le projet conserve aussi un instantané WSMC de 1 881 entrées (1 168 blocs, 490 items, 223 mobs), issu de Minecraft 1.21.11. Cette référence reste historique. La nouvelle API fournit la connaissance et les candidats de palette ; la traduction de modèles d’entités en structures (visage de creeper, squelette géant, etc.) reste un chantier distinct. Aucun générateur d’entités ni import de ce snapshot ancien n’est ajouté au registre de Minecraft 26.3 par le socle méta. ## Validation Validation locale du 10 septembre 2026 : `./gradlew check build assemblePack` passe, avec **24 GameTests natifs réussis**. Le client graphique vérifie les widgets et les messages réels dans un nouveau monde intégré, avec B sans droit opérateur, observation serveur et possession conservée après retrait du stock. Les tests de stockage passent. Les [preuves et limites](testing-alpha23.md) détaillent le protocole, l’artefact et son empreinte. Alpha.23 assemblée localement ; publication du MRpack et mise à jour du canal demandées, en préparation.