Chunk persistence to Anvil .mca region files
The world now survives restarts: chunks load from disk (read-through cache) and player edits persist via async autosave + a final SaveAll on shutdown. RegionIO finally does region I/O. - world/regionfile.go: Anvil .mca container — 8192-byte header (offset + timestamp tables), 4096-byte sectors, zlib chunk records. - world/compress.go: zlib deflate/inflate for chunk payloads. - world/store.go: chunk <-> Level-nested NBT (per-section block_states/biomes palettes, WORLD_SURFACE heightmap, DataVersion 4790, yPos -4) via the existing nbt package; Store opens one RegionFile per region with proper floor-division coords. - world/state_names.go: id->name bridge from the embedded blocks.json report so network int-IDs round-trip through the disk named palette. - world/encode.go: GetBiome read accessor for serialization. - world/cache.go: read-through (disk then generation), dirty tracking, StartAutosave (returns a done channel so the saver exits before Close), SaveAll, NewCacheWithStore. - server.go + main.go: Config.WorldDir (default "world"), -world flag, autosave loop every 30s, SaveAll + store Close on signal. - Tests: region round-trip/absent/overwrite, chunk NBT round-trip, end-to-end save-reload, negative chunk coords, autosave persistence.
This commit is contained in:
parent
4dcf938a85
commit
d1cc29bb60
10 changed files with 305112 additions and 20 deletions
|
|
@ -20,6 +20,10 @@ type Config struct {
|
|||
CompressionThreshold int
|
||||
// WorldSeed seeds terrain generation.
|
||||
WorldSeed int64
|
||||
// WorldDir is the on-disk world directory. When non-empty, chunks are
|
||||
// read from and written to <WorldDir>/region/*.mca and player edits
|
||||
// survive restarts. Empty disables persistence (in-memory only).
|
||||
WorldDir string
|
||||
}
|
||||
|
||||
// DefaultConfig returns sensible defaults matching vanilla expectations.
|
||||
|
|
@ -33,6 +37,9 @@ func DefaultConfig() Config {
|
|||
// WorldSeed defaults to 0 for backward compatibility; operators override
|
||||
// it via the REGIONIO_SEED env var or the -seed flag.
|
||||
WorldSeed: 0,
|
||||
// WorldDir defaults to "world" so the world persists by default;
|
||||
// set to "" for a throwaway in-memory world.
|
||||
WorldDir: "world",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,14 +47,26 @@ func DefaultConfig() Config {
|
|||
type Server struct {
|
||||
cfg Config
|
||||
chunks *world.Cache
|
||||
store *world.Store // nil when persistence is disabled
|
||||
}
|
||||
|
||||
// New constructs a Server from cfg.
|
||||
func New(cfg Config) *Server {
|
||||
// New constructs a Server from cfg. When cfg.WorldDir is set, the world is
|
||||
// backed by an on-disk store under that directory; otherwise it is in-memory
|
||||
// only. A returned error (e.g. the world dir cannot be created) is fatal.
|
||||
func New(cfg Config) (*Server, error) {
|
||||
gen := world.NewVanillaGenerator(cfg.WorldSeed)
|
||||
if cfg.WorldDir == "" {
|
||||
return &Server{cfg: cfg, chunks: world.NewCache(int32(cfg.CompressionThreshold), gen)}, nil
|
||||
}
|
||||
store, err := world.NewStore(cfg.WorldDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Server{
|
||||
cfg: cfg,
|
||||
chunks: world.NewCache(int32(cfg.CompressionThreshold), world.NewVanillaGenerator(cfg.WorldSeed)),
|
||||
}
|
||||
chunks: world.NewCacheWithStore(int32(cfg.CompressionThreshold), gen, store),
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Config returns the active configuration.
|
||||
|
|
@ -56,6 +75,9 @@ func (s *Server) Config() Config { return s.cfg }
|
|||
// Chunks returns the shared chunk cache.
|
||||
func (s *Server) Chunks() *world.Cache { return s.chunks }
|
||||
|
||||
// Store returns the on-disk world store, or nil if persistence is disabled.
|
||||
func (s *Server) Store() *world.Store { return s.store }
|
||||
|
||||
// statusResponse mirrors the JSON shape the client expects for the server-list
|
||||
// ping. Field names and nesting are part of the protocol contract.
|
||||
type statusResponse struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue