Skip to content

Commit

Permalink
Scan blocks along Y axis
Browse files Browse the repository at this point in the history
  • Loading branch information
weqqr committed Oct 29, 2024
1 parent dc72bec commit 8c31048
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 12 deletions.
23 changes: 15 additions & 8 deletions cmd/panorama/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/lord-server/panorama/internal/config"
"github.com/lord-server/panorama/internal/game"
"github.com/lord-server/panorama/internal/generator"
"github.com/lord-server/panorama/internal/generator/isometric"
"github.com/lord-server/panorama/internal/generator/flat"
"github.com/lord-server/panorama/internal/generator/tile"
"github.com/lord-server/panorama/internal/server"
"github.com/lord-server/panorama/internal/world"
Expand Down Expand Up @@ -64,20 +64,27 @@ func fullrender(config config.Config) error {
return err
}

backend, err := world.NewPostgresBackend(config.System.WorldDSN)
wd, err := world.NewWorld(config.System.WorldPath)
if err != nil {
slog.Error("unable to connect to world DB", "error", err)
return err
}
slog.Error("unable to open world, falling back to DSN",
"err", err,
"world_path", config.System.WorldPath)

world := world.NewWorldWithBackend(backend)
backend, err := world.NewPostgresBackend(config.System.WorldDSN)
if err != nil {
slog.Error("unable to connect to world DB", "error", err)
return err
}

wd = world.NewWorldWithBackend(backend)
}

tiler := tile.NewTiler(config.Region, config.Renderer.ZoomLevels, config.System.TilesPath)

slog.Info("performing a full render", "workers", config.Renderer.Workers, "region", config.Region)

tiler.FullRender(&game, &world, config.Renderer.Workers, config.Region, func() generator.Renderer {
return isometric.NewRenderer(config.Region, &game)
tiler.FullRender(&game, &wd, config.Renderer.Workers, config.Region, func() generator.Renderer {
return flat.NewRenderer(config.Region, &game)
})

tiler.DownscaleTiles()
Expand Down
5 changes: 3 additions & 2 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ game_path = "/var/lib/panorama/game"
world_path = "/var/lib/panorama/world"

# Path to the directory containing the mods
# Default: "/var/lib/panorama/mods"
mod_path = "/var/lib/panorama/mods"


# DSN string used for connecting to PostgreSQL
# DSN string used for connecting to PostgreSQL. Overrides DSN found in
# world_path
# Default: ""
world_dsn = ""

Expand Down
6 changes: 6 additions & 0 deletions internal/game/media.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ func NewMediaCache() *MediaCache {

func (m *MediaCache) fetchMedia(path string) error {
return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
if err != nil {
slog.Warn("encountered error while fetching media", "error", err, "dir_entry", d)

return nil
}

if !d.Type().IsRegular() {
return nil
}
Expand Down
21 changes: 19 additions & 2 deletions internal/generator/flat/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package flat

import (
"image"
"log/slog"

"github.com/lord-server/panorama/internal/game"
"github.com/lord-server/panorama/internal/generator"
Expand All @@ -28,15 +29,31 @@ func NewRenderer(region geom.Region, game *game.Game) *FlatRenderer {

func (r *FlatRenderer) RenderTile(
tilePos generator.TilePosition,
world *world.World,
wd *world.World,
game *game.Game,
) *rasterizer.RenderBuffer {
rect := image.Rect(0, 0, 256, 256)
target := rasterizer.NewRenderBuffer(rect)

err := wd.GetBlocksAlongY(tilePos.X, tilePos.Y, func(pos geom.BlockPosition, block *world.MapBlock) error {
return nil
})
if err != nil {
slog.Error("unable to get blocks", "error", err)
}

return target
}

func (r *FlatRenderer) ProjectRegion(region geom.Region) geom.ProjectedRegion {
return geom.ProjectedRegion{}
return geom.ProjectedRegion{
XBounds: geom.Bounds{
Min: region.XBounds.Min / 16,
Max: region.XBounds.Max / 16,
},
YBounds: geom.Bounds{
Min: region.ZBounds.Min / 16,
Max: region.ZBounds.Max / 16,
},
}
}
41 changes: 41 additions & 0 deletions internal/world/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package world

import (
"bufio"
"fmt"
"os"
"strings"
)

type Meta map[string]string

func ParseMeta(path string) (Meta, error) {
meta := make(map[string]string)

file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("can't read world metadata: %w", err)
}

defer file.Close()

sc := bufio.NewScanner(file)

for sc.Scan() {
parts := strings.SplitN(sc.Text(), "=", 2)
if len(parts) != 2 {
continue
}

key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])

meta[key] = value
}

if err := sc.Err(); err != nil {
return nil, err
}

return meta, nil
}
95 changes: 95 additions & 0 deletions internal/world/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package world
import (
"context"
"errors"
"fmt"
"path/filepath"

lru "github.com/hashicorp/golang-lru/v2"
"github.com/jackc/pgx/v5"
Expand All @@ -12,6 +14,7 @@ import (

type Backend interface {
GetBlockData(pos geom.BlockPosition) ([]byte, error)
GetBlocksAlongY(x, z int, callback func(geom.BlockPosition, []byte) error) error
Close()
}

Expand Down Expand Up @@ -49,11 +52,80 @@ func (p *PostgresBackend) GetBlockData(pos geom.BlockPosition) ([]byte, error) {
return data, nil
}

func (p *PostgresBackend) GetBlocksAlongY(x, z int, callback func(geom.BlockPosition, []byte) error) error {
rows, err := p.conn.Query(context.Background(), "SELECT posx, posy, posz, data FROM blocks WHERE posx=$1 and posz=$2 ORDER BY posy", x, z)
if errors.Is(err, pgx.ErrNoRows) {
return nil
}

if err != nil {
return err
}

defer rows.Close()

for rows.Next() {
var (
pos geom.BlockPosition
data []byte
)

err = rows.Scan(&pos.X, &pos.Y, &pos.Z, &data)
if err != nil {
return err
}

err = callback(pos, data)
if err != nil {
return err
}
}

rows.Close()

if err := rows.Err(); err != nil {
return err
}

return nil
}

type World struct {
backend Backend
decodedBlockCache *lru.Cache[geom.BlockPosition, *MapBlock]
}

func NewWorld(path string) (World, error) {
var world World

meta, err := ParseMeta(filepath.Join(path, "world.mt"))
if err != nil {
return world, err
}

backendName, ok := meta["backend"]
if !ok {
return world, errors.New("backend not specified")
}

var backend Backend

switch backendName {
case "postgresql":
dsn, ok := meta["pgsql_connection"]
if !ok {
return world, errors.New("postgresql connection not specified")
}

backend, err = NewPostgresBackend(dsn)
if err != nil {
return world, fmt.Errorf("unable to create PostgreSQL backend: %w", err)
}
}

return NewWorldWithBackend(backend), nil
}

func NewWorldWithBackend(backend Backend) World {
decodedBlockCache, err := lru.New[geom.BlockPosition, *MapBlock](1024 * 16)
if err != nil {
Expand Down Expand Up @@ -96,3 +168,26 @@ func (w *World) GetBlock(pos geom.BlockPosition) (*MapBlock, error) {

return block, nil
}

func (w *World) GetBlocksAlongY(x, z int, callback func(geom.BlockPosition, *MapBlock) error) error {
return w.backend.GetBlocksAlongY(x, z, func(pos geom.BlockPosition, data []byte) error {
cachedBlock, ok := w.decodedBlockCache.Get(pos)

if ok {
if cachedBlock == nil {
return nil
}

return callback(pos, cachedBlock)
}

block, err := DecodeMapBlock(data)
if err != nil {
return err
}

w.decodedBlockCache.Add(pos, block)

return callback(pos, block)
})
}

0 comments on commit 8c31048

Please sign in to comment.