package main import ( "encoding/json" "errors" "fmt" "os" "path" "strconv" "strings" ) type World struct { Name string `json:"name"` Width uint64 `json:"width"` Height uint64 `json:"height"` TileIndex *TileIndex `json:"-"` Map []uint64 `json:"-"` } func NewWorld(name string, size *Vec2) *World { return &World{ Name: name, Width: uint64(size.X), Height: uint64(size.Y), TileIndex: &TileIndex{}, Map: make([]uint64, size.X*size.Y), } } func (w *World) AddTile(symbol string, color string) uint64 { w.TileIndex.Tiles = append(w.TileIndex.Tiles, &Tile{Symbol: symbol, Color: color}) return uint64(len(w.TileIndex.Tiles)) } func LoadWorld(worlddir string) (*World, error) { var ( w *World = &World{} err error ) payload, err := os.ReadFile(path.Join(worlddir, "world.json")) if err != nil { return nil, err } err = json.Unmarshal(payload, &w) if err != nil { return nil, err } w.Map = make([]uint64, 0, w.Width*w.Height) ti, err := ParseTileIndex(path.Join(worlddir, "tiles.txt")) if err != nil { return nil, err } w.TileIndex = ti payload, err = os.ReadFile(path.Join(worlddir, "map.dat")) if err != nil { return nil, err } var ( line string = "" linenum int = 0 ) for _, b := range payload { if b == '\n' { linenum += 1 parts := strings.Split(strings.TrimSpace(line), " ") if len(parts) != int(w.Width) { return nil, fmt.Errorf("%d]: Failed parsing Map Data, not enough parts (expected=%d, got=%d), '%s'", linenum, w.Width, len(parts), line) } for segnum, p := range parts { t, err := strconv.ParseUint(p, 10, 64) if err != nil { return nil, fmt.Errorf("%d]: Failed parsing Map Data, line segment #%d errored %v, '%s'", linenum, segnum, err, line) } w.Map = append(w.Map, t) } line = "" } else { line += string(b) } } return w, nil } func (w *World) Save(dirname string) error { stat, err := os.Stat(dirname) if err != nil { if errors.Is(err, os.ErrNotExist) { err1 := os.MkdirAll(dirname, 0775) if err1 != nil { return fmt.Errorf("%v >> %v", err, err1) } } else { return err } } if stat != nil { if !stat.IsDir() { err = os.Remove(dirname) if err != nil { return err } err := os.MkdirAll(dirname, 0775) if err != nil { return err } } } payload, err := json.Marshal(w) if err != nil { return err } err = os.WriteFile(path.Join(dirname, "world.json"), payload, 0666) if err != nil { return err } err = w.TileIndex.Save(path.Join(dirname, "tiles.txt")) if err != nil { return err } f, err := os.Create(path.Join(dirname, "map.dat")) if err != nil { return err } defer f.Close() var idx int = 0 for _, t := range w.Map { if idx >= int(w.Width) { _, err = f.WriteString("\n") if err != nil { return err } idx -= int(w.Width) } _, err = f.WriteString(fmt.Sprintf("%d ", t)) if err != nil { return err } idx += 1 } return nil } func (w *World) Get(x, y uint64) uint64 { idx := (y * w.Width) + x max := w.Width * w.Height if idx >= max { return 0 } return w.Map[idx] } func (w *World) Set(x, y, t uint64) bool { idx := (y * w.Width) + x max := w.Width * w.Height if idx >= max { return false } w.Map[idx] = t return true }