change: Finished loading command and added some scripts for extracting world saves
This commit is contained in:
		@@ -1,71 +1,46 @@
 | 
			
		||||
package loading
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"git.nicholasnovak.io/nnovak/spatial-db/world"
 | 
			
		||||
	"github.com/Tnze/go-mc/save"
 | 
			
		||||
	"github.com/Tnze/go-mc/save/region"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SectorPos struct {
 | 
			
		||||
	x, y int
 | 
			
		||||
}
 | 
			
		||||
// LoadRegionFile loads a single region file into an array of chunks
 | 
			
		||||
//
 | 
			
		||||
// A region is a 32x32 grid of chunks, although the final output can store less
 | 
			
		||||
func LoadRegionFile(fileName string) ([]world.ChunkData, error) {
 | 
			
		||||
	regionFile, err := region.Open(fileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer regionFile.Close()
 | 
			
		||||
 | 
			
		||||
var outputDir string
 | 
			
		||||
	// A region file is a 32x32 grid of chunks
 | 
			
		||||
	chunks := []world.ChunkData{}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	LoadRegionFileCommand.Flags().StringVar(&outputDir, "output", ".", "The output directory for the files")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var LoadRegionFileCommand = &cobra.Command{
 | 
			
		||||
	Use: "load",
 | 
			
		||||
	RunE: func(cmd *cobra.Command, args []string) error {
 | 
			
		||||
		regionFile, err := region.Open(args[0])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defer regionFile.Close()
 | 
			
		||||
 | 
			
		||||
		validSectors := []SectorPos{}
 | 
			
		||||
 | 
			
		||||
		for i := 0; i < 32; i++ {
 | 
			
		||||
			for j := 0; j < 32; j++ {
 | 
			
		||||
				if regionFile.ExistSector(i, j) {
 | 
			
		||||
					validSectors = append(validSectors, SectorPos{i, j})
 | 
			
		||||
	for i := 0; i < 32; i++ {
 | 
			
		||||
		for j := 0; j < 32; j++ {
 | 
			
		||||
			if regionFile.ExistSector(i, j) {
 | 
			
		||||
				sectorFile, err := regionFile.ReadSector(i, j)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Read each chunk from disk
 | 
			
		||||
				var chunk save.Chunk
 | 
			
		||||
				if err := chunk.Load(sectorFile); err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Convert each chunk into the database's format
 | 
			
		||||
				var chunkData world.ChunkData
 | 
			
		||||
				chunkData.FromMCAChunk(chunk)
 | 
			
		||||
 | 
			
		||||
				chunks = append(chunks, chunkData)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		for _, sectorPos := range validSectors {
 | 
			
		||||
			data, err := regionFile.ReadSector(sectorPos.x, sectorPos.y)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var chunk save.Chunk
 | 
			
		||||
			if err := chunk.Load(data); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var chunkData world.ChunkData
 | 
			
		||||
			chunkData.FromMCAChunk(chunk)
 | 
			
		||||
 | 
			
		||||
			outfile, err := os.OpenFile(filepath.Join(outputDir, fmt.Sprintf("p.%d.%d.chunk", chunkData.Pos.X, chunkData.Pos.Z)), os.O_WRONLY|os.O_CREATE, 0644)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			if err := json.NewEncoder(outfile).Encode(chunkData); err != nil {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			outfile.Close()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
	return chunks, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										80
									
								
								loading/load_save.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								loading/load_save.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
package loading
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	saveOutputDir string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	LoadSaveDirCommand.Flags().StringVar(&saveOutputDir, "output", ".", "Where to place the converted save files")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var LoadSaveDirCommand = &cobra.Command{
 | 
			
		||||
	Use:   "worldsave <save-directory>",
 | 
			
		||||
	Short: "Loads all the regions in the specified world's save directory",
 | 
			
		||||
	Args:  cobra.ExactArgs(1),
 | 
			
		||||
	RunE: func(cmd *cobra.Command, args []string) error {
 | 
			
		||||
		// First, fetch a list of all the files that are in the specified directory
 | 
			
		||||
		regionFiles, err := os.ReadDir(args[0])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Infof("Loading save directory of %s", args[0])
 | 
			
		||||
 | 
			
		||||
		for regionIndex, regionFile := range regionFiles {
 | 
			
		||||
			if regionFile.IsDir() {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if strings.HasSuffix(regionFile.Name(), ".mcr") {
 | 
			
		||||
				log.Warnf("The file %s is in the MCRegion format, skipping", regionFile.Name())
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			log.Infof("Converting region file %s, [%d/%d]",
 | 
			
		||||
				regionFile.Name(),
 | 
			
		||||
				regionIndex,
 | 
			
		||||
				len(regionFiles),
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			filePath := filepath.Join(args[0], regionFile.Name())
 | 
			
		||||
 | 
			
		||||
			// Load each region file
 | 
			
		||||
			chunks, err := LoadRegionFile(filePath)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Save each chunk to a separate file
 | 
			
		||||
			for _, chunk := range chunks {
 | 
			
		||||
				outfile, err := os.OpenFile(
 | 
			
		||||
					filepath.Join(saveOutputDir, chunk.Pos.ToFileName()),
 | 
			
		||||
					os.O_WRONLY|os.O_CREATE|os.O_APPEND,
 | 
			
		||||
					0664,
 | 
			
		||||
				)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if err := json.NewEncoder(outfile).Encode(chunk); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				outfile.Close()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user