135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/df-mc/dragonfly/server/world/mcdb"
|
|
"github.com/df-mc/goleveldb/leveldb/opt"
|
|
"github.com/google/subcommands"
|
|
"github.com/jinzhu/copier"
|
|
)
|
|
|
|
type MergeCMD struct {
|
|
worlds []string
|
|
legacy bool
|
|
}
|
|
|
|
func (*MergeCMD) Name() string { return "merge" }
|
|
func (*MergeCMD) Synopsis() string { return "merge 2 or more worlds" }
|
|
|
|
func (c *MergeCMD) SetFlags(f *flag.FlagSet) {
|
|
f.BoolVar(&c.legacy, "legacy", false, "if the worlds are before 1.18")
|
|
}
|
|
func (c *MergeCMD) Usage() string {
|
|
return c.Name() + ": " + c.Synopsis() + "\n"
|
|
}
|
|
|
|
func (c *MergeCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
|
if f.NArg() == 0 {
|
|
fmt.Println("you need to specify 1 or more worlds")
|
|
return 1
|
|
}
|
|
c.worlds = f.Args()
|
|
out_name := c.worlds[0] + "-merged"
|
|
|
|
prov_out, err := mcdb.New(out_name, opt.DefaultCompression)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to open output %s\n", err)
|
|
}
|
|
|
|
for i, world_name := range c.worlds {
|
|
first := i == 0
|
|
fmt.Printf("Adding %s\n", world_name)
|
|
s, err := os.Stat(world_name)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
fmt.Fprintf(os.Stderr, "%s not found\n", world_name)
|
|
}
|
|
if !s.IsDir() {
|
|
f, _ := os.Open(world_name)
|
|
world_name += "_unpack"
|
|
unpack_zip(f, s.Size(), world_name)
|
|
}
|
|
err = c.merge_worlds(prov_out, world_name, first)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s %s\n", world_name, err)
|
|
}
|
|
if !s.IsDir() {
|
|
os.RemoveAll(world_name)
|
|
}
|
|
}
|
|
|
|
if err = prov_out.Close(); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return 1
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
|
|
if err := zip_folder(out_name+".mcworld", out_name); err != nil {
|
|
fmt.Fprintf(os.Stderr, "zipping: %s\n", err)
|
|
return 1
|
|
}
|
|
|
|
//os.RemoveAll(out_name)
|
|
return 0
|
|
}
|
|
|
|
func (c *MergeCMD) merge_worlds(prov_out *mcdb.Provider, folder string, first bool) error {
|
|
prov_in, err := mcdb.New(folder, opt.DefaultCompression)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
count := 0
|
|
existing := prov_out.Chunks(c.legacy)
|
|
new := prov_in.Chunks(c.legacy)
|
|
for i := range new {
|
|
if _, ok := existing[i]; !ok {
|
|
d := i.D
|
|
// chunks
|
|
ch, _, err := prov_in.LoadChunk(i.P, d)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := prov_out.SaveChunk(i.P, ch, i.D); err != nil {
|
|
return err
|
|
}
|
|
|
|
// blockNBT
|
|
n, err := prov_in.LoadBlockNBT(i.P, i.D)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := prov_out.SaveBlockNBT(i.P, n, i.D); err != nil {
|
|
return err
|
|
}
|
|
|
|
// entities
|
|
entities, err := prov_in.LoadEntities(i.P, i.D)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := prov_out.SaveEntities(i.P, entities, i.D); err != nil {
|
|
return err
|
|
}
|
|
count += 1
|
|
}
|
|
}
|
|
|
|
if first {
|
|
fmt.Print("Applying Settings, level.dat\n\n")
|
|
prov_out.SaveSettings(prov_in.Settings())
|
|
out_ld := prov_out.LevelDat()
|
|
copier.Copy(out_ld, prov_in.LevelDat())
|
|
}
|
|
fmt.Printf("Added: %d\n", count)
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
register_command(&MergeCMD{})
|
|
}
|