Sistema de Checkpoints

Un servei de checkpoints per slots que separa la regla de negoci de quan guardar del detall d'emmagatzematge de com i on.

Per a què serveix aquest sistema

Tot joc que permet als jugadors guardar el seu progrés acaba escrivint la mateixa infraestructura. La gestió de slots, la serialització, les rutes d'arxiu, les escriptures atòmiques i la validació de càrrega s'acumulen en una massa embolicada que és difícil de provar i encara més difícil de substituir quan canvia el mitjà d'emmagatzematge.

El sistema de Checkpoints de Serenity ofereix una única interfície de servei a la qual cridar en guardar, carregar o eliminar l'estat del joc. El blob serialitzat es tracta com un array de bytes opac, de manera que la regla de negoci que determina quan es pot prendre un checkpoint està completament desacoblada del backend d'emmagatzematge que el persisteix.

El problema a Unity

Un sistema de guardatge a Unity que creix de forma orgànica tendeix a barrejar responsabilitats. El codi que decideix quan guardar un checkpoint acaba sabent sobre rutes d'arxiu, formats JSON o claus de PlayerPrefs. El codi que llegeix un slot de guardatge acaba deserialitzant directament dins d'un MonoBehaviour. Quan cal afegir un nou slot, canviar el backend d'emmagatzematge o donar suport a guardatges al núvol, l'abast de l'impacte és impredictible.

Sense un límit clar entre el disparador del guardatge i el mecanisme d'emmagatzematge, les proves són manuals i cada canvi d'emmagatzematge requereix tocar la lògica del joc. El resultat són bugs de guardatge que només apareixen en certes plataformes o després de seqüències de sessió específiques.

Com ho aborda Serenity

Serenity exposa el comportament de checkpoint a través d'ICheckpointService, que ofereix Save, TryLoad, HasCheckpoint, Delete i QueryAvailable. Els slots es modelen mitjançant l'enum CheckpointSlot, que defineix Auto, Manual1, Manual2, Manual3 i QuickSave. Cada guardatge produeix un CheckpointId i s'associa amb un valor CheckpointMetadata que registra un timestamp, una etiqueta i un nom de fase.

El costat de l'emmagatzematge s'abstrau darrere d'ICheckpointStore, i el model de lectura immutable retornat en la càrrega és CheckpointSnapshot, que transporta el slot, l'array de bytes opac i els metadades. La infraestructura concreta utilitza UnityCheckpointStore connectat a través d'UnityCheckpointInstaller, situat sobre la jerarquia de ports de Persistence i FilePersistence per a escriptures atòmiques en arxiu.

Com encaixa a Serenity

El sistema de Checkpoints viu al namespace Serenity.Checkpoint i segueix l'estructura per capes de la foundation. La capa de Domini defineix l'enum CheckpointSlot i els value objects CheckpointId, CheckpointMetadata i CheckpointSnapshot. La capa d'Aplicació exposa ICheckpointService i ICheckpointStore com a contractes de servei i emmagatzematge. La capa d'Infraestructura proporciona UnityCheckpointService i UnityCheckpointStore. La capa d'Instal·lació connecta tot a través de CheckpointInstaller i UnityCheckpointInstaller.

Checkpoint es compon amb la jerarquia de ports de Persistence — IPersistenceStore, IBlobStore, IKeyValueStore — i amb FilePersistence, que proporciona escriptures atòmiques en arxiu a través de FileStore i IFileWriterService. Això significa que canviar el backend d'emmagatzematge és qüestió de proporcionar una implementació diferent d'ICheckpointStore sense tocar cap lògica de negoci.

Flux de treball pràctic

  1. Implementa o configura el serialitzador de l'estat del joc per produir un array de bytes que representi l'estat actual.
  2. Crida a ICheckpointService.Save amb el CheckpointSlot de destinació, l'array de bytes i un CheckpointMetadata que descrigui el punt de guardatge.
  3. En la càrrega, crida a TryLoad amb un CheckpointSlot o un CheckpointId i rep un CheckpointSnapshot amb les dades opaques i els seus metadades.
  4. Fes servir QueryAvailable per llistar tots els checkpoints existents i construir la interfície de slots de guardatge a partir de l'array de CheckpointMetadata retornat.
  5. Crida a HasCheckpoint abans de sobreescriure un slot per detectar conflictes i sol·licitar confirmació al jugador.
  6. Crida a Delete per eliminar un slot quan el jugador esborra un arxiu de guardatge.

Què inclou

  • Servei de checkpoint ICheckpointService amb Save, TryLoad, HasCheckpoint, Delete i QueryAvailable
  • Enum de slot CheckpointSlot que defineix Auto, Manual1, Manual2, Manual3 i QuickSave
  • Model de lectura immutable CheckpointSnapshot amb slot, array de bytes opac i metadades
  • Value object CheckpointMetadata amb ticks de timestamp, etiqueta i nom de fase
  • Identificador estable CheckpointId com a struct immutable amb generació de GUID
  • Port d'emmagatzematge ICheckpointStore completament desacoblat de les regles de negoci
  • Infraestructura concreta UnityCheckpointStore i UnityCheckpointInstaller per a projectes Unity
  • Composició amb FilePersistence i FileStore per a escriptures atòmiques i segures a la plataforma

Quan fer-lo servir

  • Jocs que necessiten slots de guardatge amb nom — autoguardatge, guardatge ràpid i múltiples slots manuals — sense acoblar la lògica de slots a l'E/S d'arxius.
  • Projectes que necessiten canviar o combinar backends d'emmagatzematge, per exemple passar d'arxius locals a guardatges al núvol, sense reescriure la lògica del joc.
  • Bases de codi que volen el comportament de guardatge i càrrega cobert per proves unitàries que s'executin sense un sistema d'arxius.
  • Equips que volen una interfície de guardatge coherent utilitzable en diferents escenes i modes de joc, coordinada amb Game Session i Game Settings.

Sistemes relacionats

Utilitza Serenity quan vulguis un comportament de guardatge i càrrega que ja parli amb la gestió de sessió i els ajustos del joc, però que segueixi tractant el format de serialització i el mitjà d'emmagatzematge com a detalls intercanviables de forma independent.

Tornar a la pàgina principal