github.com/df-mc/dragonfly@v0.9.13/server/world/mcdb/conf.go (about)

     1  package mcdb
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/df-mc/dragonfly/server/entity"
     6  	"github.com/df-mc/dragonfly/server/world"
     7  	"github.com/df-mc/dragonfly/server/world/mcdb/leveldat"
     8  	"github.com/df-mc/goleveldb/leveldb"
     9  	"github.com/df-mc/goleveldb/leveldb/opt"
    10  	"github.com/sirupsen/logrus"
    11  	"os"
    12  	"path/filepath"
    13  )
    14  
    15  // Logger is a logger implementation that may be passed to the Log field of Config. World will send errors and debug
    16  // messages to this Logger when appropriate.
    17  type Logger interface {
    18  	Errorf(format string, a ...any)
    19  	Debugf(format string, a ...any)
    20  }
    21  
    22  // Config holds the optional parameters of a DB.
    23  type Config struct {
    24  	// Log is the Logger that will be used to log errors and debug messages to.
    25  	// If set to nil, a Logrus logger will be used.
    26  	Log Logger
    27  	// Compression specifies the compression to use for compressing new data in
    28  	// the database. Decompression of the database will happen based on IDs
    29  	// found in the compressed blocks and is therefore uninfluenced by this
    30  	// field. If left empty, Compression will default to opt.FlateCompression.
    31  	Compression opt.Compression
    32  	// BlockSize specifies the size of blocks to be compressed. The default
    33  	// value, when left empty, is 16KiB (16 * opt.KiB). Higher values generally
    34  	// lead to better compression ratios at the expense of slightly higher
    35  	// memory usage while (de)compressing.
    36  	BlockSize int
    37  	// ReadOnly opens the DB in read-only mode. This will leave the data in the
    38  	// database unedited.
    39  	ReadOnly bool
    40  
    41  	// Entities is an EntityRegistry with all entity types registered that may
    42  	// be read from the DB. Entities will default to entity.DefaultRegistry.
    43  	Entities world.EntityRegistry
    44  }
    45  
    46  // Open creates a new DB reading and writing from/to files under the path
    47  // passed. If a world is present at the path, Open will parse its data and
    48  // initialise the world with it. If the data cannot be parsed, an error is
    49  // returned.
    50  func (conf Config) Open(dir string) (*DB, error) {
    51  	if conf.Log == nil {
    52  		conf.Log = logrus.New()
    53  	}
    54  	if conf.BlockSize == 0 {
    55  		conf.BlockSize = 16 * opt.KiB
    56  	}
    57  	if len(conf.Entities.Types()) == 0 {
    58  		conf.Entities = entity.DefaultRegistry
    59  	}
    60  	_ = os.MkdirAll(filepath.Join(dir, "db"), 0777)
    61  
    62  	db := &DB{conf: conf, dir: dir, ldat: &leveldat.Data{}}
    63  	if _, err := os.Stat(filepath.Join(dir, "level.dat")); os.IsNotExist(err) {
    64  		// A level.dat was not currently present for the world.
    65  		db.ldat.FillDefault()
    66  	} else {
    67  		ldat, err := leveldat.ReadFile(filepath.Join(dir, "level.dat"))
    68  		if err != nil {
    69  			return nil, fmt.Errorf("open db: %w", err)
    70  		}
    71  
    72  		// TODO: Perform proper conversion here. Dragonfly stored 3 for a long
    73  		//  time even though the fields were up to date, so we have to accept
    74  		//  older ones no matter what.
    75  		ver := ldat.Ver()
    76  		if ver != leveldat.Version && ver >= 10 {
    77  			return nil, fmt.Errorf("open db: level.dat version %v is unsupported", ver)
    78  		}
    79  		if err = ldat.Unmarshal(db.ldat); err != nil {
    80  			return nil, fmt.Errorf("open db: %w", err)
    81  		}
    82  	}
    83  	db.set = db.ldat.Settings()
    84  	ldb, err := leveldb.OpenFile(filepath.Join(dir, "db"), &opt.Options{
    85  		Compression: conf.Compression,
    86  		BlockSize:   conf.BlockSize,
    87  		ReadOnly:    conf.ReadOnly,
    88  	})
    89  	if err != nil {
    90  		return nil, fmt.Errorf("error opening leveldb database: %w", err)
    91  	}
    92  	db.ldb = ldb
    93  	return db, nil
    94  }