package storage import ( "bytes" "errors" "fmt" "image" "image/color" "image/draw" "log" "os" "time" ) var tiles [][]tile type WrongSizeError struct { ExpectedSize int ActualSize image.Point X int Y int } func (err *WrongSizeError) Error() string { return fmt.Sprintf("expected %dx%d tile, got %dx%d (coords: %d-%d)", err.ExpectedSize, err.ExpectedSize, err.ActualSize.X, err.ActualSize.Y, err.X, err.Y) } func Load(path string, canvasSize int, tileSize int) { if err := os.Chdir(path); err != nil { panic(err) } tiles = make([][]tile, canvasSize) for i := range tiles { tiles[i] = make([]tile, canvasSize) } for y := range tiles { for x := range tiles[y] { tiles[y][x].image = image.NewRGBA(image.Rect(0, 0, tileSize, tileSize)) filename := fmt.Sprintf("%d-%d.png", x, y) file, err := os.Open(filename) if err != nil { tiles[y][x].fill() if err = tiles[y][x].save(filename); err != nil { panic(err) } log.Printf("Created tile (%d-%d)\n", x, y) } else { img, _, err := image.Decode(file) if err != nil { panic(err) } draw.Draw(tiles[y][x].image, img.Bounds(), img, img.Bounds().Min, draw.Src) } defer file.Close() if tiles[y][x].image.Bounds().Size().X != tileSize && tiles[y][x].image.Bounds().Size().Y != tileSize { panic(WrongSizeError{ExpectedSize: tileSize, ActualSize: tiles[y][x].image.Bounds().Size(), X: x, Y: y}) } tiles[y][x].dirty = false } } } func Save() { for y := range tiles { for x := range tiles[y] { if tiles[y][x].dirty { filename := fmt.Sprintf("%d-%d.png", x, y) if err := tiles[y][x].save(filename); err != nil { panic(err) } } } } } func StartSaves(saveFrequency int) { go func() { for range time.Tick(time.Second * time.Duration(saveFrequency)) { Save() } }() } func GetTile(x int, y int) (*bytes.Buffer, error) { if x >= len(tiles) || y >= len(tiles) { return nil, errors.New("tile coordinates out of range") } return tiles[y][x].toBytesPNG() } func SetPixel(x int, y int, c color.Color) error { size := tiles[0][0].size() var tx int = x / size.X var ty int = y / size.Y x = x % size.X y = y % size.Y if ty >= len(tiles) || tx >= len(tiles[ty]) { return errors.New("coordinates out of range") } tiles[ty][tx].image.Set(x, y, c) tiles[ty][tx].dirty = true return nil }