package world import ( "fmt" "os" "path/filepath" "strings" ) // Summary describes a discovered Minecraft world directory. type Summary struct { Name string `json:"name"` Path string `json:"path"` SizeBytes int64 `json:"sizeBytes"` HasLevelDat bool `json:"hasLevelDat"` } // ValidateWorld checks that a world directory contains level.dat. func ValidateWorld(dataPath, worldName string) error { worldName = strings.TrimSpace(worldName) if worldName == "" || strings.Contains(worldName, "..") || strings.ContainsAny(worldName, `/\`) { return fmt.Errorf("invalid world name") } worldDir := filepath.Join(dataPath, worldName) levelDat := filepath.Join(worldDir, "level.dat") info, err := os.Stat(levelDat) if err != nil { return fmt.Errorf("level.dat not found in world directory") } if info.IsDir() { return fmt.Errorf("level.dat is not a file") } return nil } // ListWorlds scans the server data directory for world folders. func ListWorlds(dataPath, activeWorldName string) ([]Summary, error) { entries, err := os.ReadDir(dataPath) if err != nil { return nil, err } worlds := make([]Summary, 0) for _, entry := range entries { if !entry.IsDir() || strings.HasPrefix(entry.Name(), ".") { continue } worldPath := filepath.Join(dataPath, entry.Name()) levelDat := filepath.Join(worldPath, "level.dat") hasLevelDat := false if info, err := os.Stat(levelDat); err == nil && !info.IsDir() { hasLevelDat = true } size, err := dirSize(worldPath) if err != nil { return nil, err } worlds = append(worlds, Summary{ Name: entry.Name(), Path: entry.Name(), SizeBytes: size, HasLevelDat: hasLevelDat, }) } if activeWorldName != "" { found := false for _, world := range worlds { if world.Name == activeWorldName { found = true break } } if !found { if err := ValidateWorld(dataPath, activeWorldName); err == nil { size, sizeErr := dirSize(filepath.Join(dataPath, activeWorldName)) if sizeErr != nil { return nil, sizeErr } worlds = append(worlds, Summary{ Name: activeWorldName, Path: activeWorldName, SizeBytes: size, HasLevelDat: true, }) } } } return worlds, nil } func dirSize(root string) (int64, error) { var total int64 err := filepath.Walk(root, func(_ string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { total += info.Size() } return nil }) return total, err }