Condividi tramite


Memorizzazione degli attori in Minecraft: Bedrock Edition

Minecraft ha ispirato molte terze parti a creare utili strumenti di visualizzazione e modifica dei file del mondo che esistono al di fuori del client. Strumenti come Universal Minecraft Editor e MCEdit sono i preferiti della community e dipendono dal sapere dove trovare i singoli dati del livello su disco nei file LevelDB. Con l'aggiornamento della memorizzazione degli attori precedente alla nuova memorizzazione degli attori nella versione 1.18.3, le posizioni nei file LevelDB in cui sono memorizzati i dati degli attori sono cambiate e questi sviluppatori di terze parti devono esserne consapevoli.

Come funzionava la memorizzazione dei dati degli attori legacy?

Prima della versione 1.18.3, i dati degli attori erano memorizzati per chunk come un insieme indefinito di tutti gli attori nel chunk specifico. Questo significava che ogni volta che un singolo attore cambiava, era necessario:

  • raccogliere i dati da ogni singolo attore nel chunk
  • aggiunge i dati per ogni attore in un unico buffer/blob
  • scrivere tali dati raggruppati nel chunk

Perché stiamo spostando i dati degli attori?

Nel formato legacy di memorizzazione dei dati degli attori, se un attore in un chunk veniva cambiato era necessario salvarli tutti, anche se solo uno era effettivamente cambiato. Questo comportava moltissime operazioni non necessarie e rendeva la gestione del trasferimento di entità tra chunk un sistema costoso e vulnerabile.

Come avviene la nuova memorizzazione su disco dei dati degli attori?

La nuova memorizzazione degli attori comporta la memorizzazione di ogni attore sotto una chiave LevelDB individuale univoca. Questo ci consente di avere operazioni di salvataggio che agiscono solo nei singoli attori. Questo significa anche che non c'è una coppia chiave-valore per tutti gli attori in un chunk. Infatti le chiavi dei singoli attori sono separate nel relativo spazio chiave dal resto dei dati dei chunk e i chunk non hanno dati sul disco che fanno direttamente riferimento agli attori che contengono.

Usiamo invece i dati dei chunk per generare in modo deterministico una chiave che è univoca per il chunk in cui memorizziamo un digest delle chiavi LevelDB per gli attori nel chunk. Queste voci del digest sono anche separate dai dati dei chunk dei non attori e dallo spazio chiave degli attori.

Diamo un'occhiata a come questo appare su disco:

Il diagramma LevelBD mostra lo spazio chiave dei chunk, lo spazio chiave dei digest degli attori e lo spazio chiave degli attori

Spazio chiave dei chunk

Sulla sinistra del diagramma possiamo vedere lo spazio della chiave dei chunk. Queste chiavi prendono la forma di chiave chunk legacy di <Chunk Position><DimensionID>. Vi è un formato chunk legacy obsoleto in cui non è presente un ID di dimensione, pertanto è possibile caricare un mondo molto vecchio in cui le chiavi dei chunk non hanno un ID di dimensione. Saranno salvate sotto una nuova chiave con l'ID di dimensione. Questo è un comportamento obsoleto che esiste ancora.

Queste sono le chiavi più piccole utilizzate spingendole insieme in modo contiguo sul disco. La chiave del chunk è usata come prefisso per le chiavi che memorizzano tutti i dati dei non attori del chunk. Ogni tipo di dati del chunk ha il proprio ID chiave che viene aggiunto al prefisso della chiave del chunk.

ID delle chiavi chunk dei dati dei non attori


enum class LevelChunkTag : char {
  Data3D = 43,
  Version, // This was moved to the front as needed for the extended heights feature. Old chunks will not have this data.
  Data2D,
  Data2DLegacy,
  SubChunkPrefix,
  LegacyTerrain,
  BlockEntity,
  Entity, // Legacy actor storage which will be deleted from LevelDB upon upgrading the chunk to use modern actor storage
  PendingTicks,
  LegacyBlockExtraData,
  BiomeState,
  FinalizedState,
  ConversionData, // Data that the converter provides that are used at runtime for things like blending
  BorderBlocks,
  HardcodedSpawners,
  RandomTicks,
  CheckSums,
  GenerationSeed,
  GeneratedPreCavesAndCliffsBlending,
  BlendingBiomeHeight,
  LegacyVersion = 118
};

Spazio chiave attori dei digest degli attori

Al centro abbiamo lo spazio chiave dei digest. Ogni chiave digest ha la forma dg<Chunk Key>.

  • dg è un prefisso codificato utilizzato per tutte le chiavi dei digest. Questo forza tutti i digest a essere contigui sul disco e aumenta le dimensioni di tutte le chiavi digest in modo tale che siano posizionate prima dei dati dei chunk dei non attori nel LevelDB.

  • <Chunk Key> è la stessa stringa chiave usata dal chunk a cui sono associati i dati.

Spazio chiave attori

Sulla destra abbiamo lo spazio chiave degli attori. Ogni chiave attore ha la forma actorpref<ActorUniqueID>.

  • actorpref è un prefisso codificato utilizzato per tutte le chiavi degli attori. Questo forza tutti i dati degli attori a essere contigui sul disco e aumenta le dimensioni di tutte le chiavi attori in modo che siano posizionate prima dei dati dei chunk dei non attori e di tutti i digest nel LevelDB.

  • <ActorUniqueID> è un ID unico che viene generato per ogni attore quando viene aggiunto al livello. Questo ID è coerente tra le sessioni di gioco ed è unico solo per questo mondo. Altri attori in altri mondi possono avere lo stesso ID, ma nessun attore nello stesso mondo avrà lo stesso ID.