1
0
forked from MTSR/mapserver

atom .Merge branch 'master' of github.com:thomasrudin-mt/mapserver

This commit is contained in:
Thomas Rudin 2019-01-26 10:21:01 +01:00
commit 4f8983141e
21 changed files with 300 additions and 55 deletions

5
.travis.yml Normal file
View File

@ -0,0 +1,5 @@
language: go
go:
- "1.11"

View File

@ -1,7 +1,7 @@
Minetest mapserver
=======
Relatime mapserver for Minetest
Realtime mapserver for Minetest
# Development state

View File

@ -1,6 +1,7 @@
STATIC_VFS=vfs/static.go
OUT_DIR=output
ENV=GO111MODULE=on
all: build
@ -8,25 +9,21 @@ $(OUT_DIR):
mkdir $@
test: $(STATIC_VFS) $(OUT_DIR)
go test ./...
$(ENV) go test ./...
clean:
rm -rf $(STATIC_VFS)
rm -rf $(OUT_DIR)
$(STATIC_VFS):
test -f ${HOME}/go/bin/esc || go get github.com/mjibson/esc
test -f esc || $(ENV) go get github.com/mjibson/esc
${HOME}/go/bin/esc -o $@ -prefix="static/" -pkg vfs static
build: $(STATIC_VFS) $(OUT_DIR)
GOOS=linux GOARCH=386 go build -o $(OUT_DIR)/mapserver-linux-x86
$(ENV) GOOS=linux GOARCH=386 go build -o $(OUT_DIR)/mapserver-linux-x86
GOOS=linux GOARCH=amd64 go build -o $(OUT_DIR)/mapserver-linux-x86_64
GOOS=linux GOARCH=arm go build -o $(OUT_DIR)/mapserver-linux-arm
GOOS=darwin GOARCH=386 go build -o $(OUT_DIR)/mapserver-darwin-x86
GOOS=darwin GOARCH=amd64 go build -o $(OUT_DIR)/mapserver-darwin-x86_64
GOOS=windows GOARCH=386 go build -o $(OUT_DIR)/mapserver-windows-x86
GOOS=windows GOARCH=amd64 go build -o $(OUT_DIR)/mapserver-windows-x86_64
profile:
go test -cpuprofile=cprof ./tilerenderer
go tool pprof --text cprof

View File

@ -13,7 +13,7 @@ import (
)
const (
Version = "0.0.1-DEV"
Version = "0.0.1-alpha"
)
type App struct {

View File

@ -24,15 +24,16 @@ func Setup(p params.ParamsType, cfg *Config) (*App, error) {
a.Worldconfig = worldconfig.Parse("world.mt")
logrus.WithFields(logrus.Fields{"version": Version}).Info("Starting mapserver")
if a.Worldconfig.Backend != worldconfig.BACKEND_SQLITE3 {
return nil, errors.New("no supported backend found!")
}
//create db accessor
var err error
a.Blockdb, err = db.NewSqliteAccessor("map.sqlite")
if err != nil {
return nil, err
switch a.Worldconfig.Backend {
case worldconfig.BACKEND_SQLITE3:
a.Blockdb, err = db.NewSqliteAccessor("map.sqlite")
if err != nil {
return nil, err
}
default:
return nil, errors.New("map-backend not supported: " + a.Worldconfig.Backend)
}
//migrate block db

View File

@ -119,3 +119,48 @@ func TestZoomedQuadrantsFromTile(t *testing.T) {
assert.Equal(t, q.LowerRight.Zoom, 13)
}
func TestZoomedOutTile(t *testing.T) {
tc := NewTileCoords(0, 0, 12, 0)
nt := tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.Zoom, 11)
tc = NewTileCoords(1, 0, 12, 0)
nt = tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.Zoom, 11)
tc = NewTileCoords(0, 1, 12, 0)
nt = tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.Zoom, 11)
tc = NewTileCoords(1, 1, 12, 0)
nt = tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.X, 0)
assert.Equal(t, nt.Zoom, 11)
tc = NewTileCoords(2, 2, 12, 0)
nt = tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 1)
assert.Equal(t, nt.X, 1)
assert.Equal(t, nt.Zoom, 11)
tc = NewTileCoords(3, 3, 12, 0)
nt = tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 1)
assert.Equal(t, nt.X, 1)
assert.Equal(t, nt.Zoom, 11)
tc = NewTileCoords(4, 4, 12, 0)
nt = tc.GetZoomedOutTile()
assert.Equal(t, nt.X, 2)
assert.Equal(t, nt.X, 2)
assert.Equal(t, nt.Zoom, 11)
}

View File

@ -21,7 +21,7 @@ func NewTileCoords(x, y, zoom int, layerId int) *TileCoords {
func (tc *TileCoords) ZoomOut(n int) *TileCoords {
var nc *TileCoords = tc
for i := 1; i < n; i++ {
for i := 0; i < n; i++ {
nc = nc.GetZoomedOutTile()
}

View File

@ -0,0 +1,38 @@
package eventbus
import (
"sync"
)
type Listener interface {
OnEvent(eventtype string, o interface{})
}
type Eventbus struct {
mutex *sync.RWMutex
listeners []Listener
}
func New() *Eventbus {
eb := Eventbus{}
eb.mutex = &sync.RWMutex{}
eb.listeners = make([]Listener, 0)
return &eb
}
func (this *Eventbus) Emit(eventtype string, o interface{}) {
this.mutex.RLock()
defer this.mutex.RUnlock()
for _, l := range this.listeners {
l.OnEvent(eventtype, o)
}
}
func (this *Eventbus) AddListener(l Listener) {
this.mutex.Lock()
defer this.mutex.Unlock()
this.listeners = append(this.listeners, l)
}

View File

@ -19,14 +19,16 @@ type Tile struct {
type MapObject struct {
//mapblock position
MBPos *coords.MapBlockCoords
MBPos *coords.MapBlockCoords `json:"mapblock"`
//block position
X, Y, Z int
X int `json:"x"`
Y int `json:"y"`
Z int `json:"z"`
Type string
Mtime int64
Attributes map[string]string
Type string `json:"type"`
Mtime int64 `json:"mtime"`
Attributes map[string]string `json:"attributes"`
}
func NewMapObject(MBPos *coords.MapBlockCoords, x int, y int, z int, _type string) *MapObject {
@ -44,16 +46,17 @@ func NewMapObject(MBPos *coords.MapBlockCoords, x int, y int, z int, _type strin
}
type SearchQuery struct {
//block position (not mapblock)
Pos1, Pos2 coords.MapBlockCoords
Type string
//mapblock position
Pos1 coords.MapBlockCoords `json:"pos1"`
Pos2 coords.MapBlockCoords `json:"pos2"`
Type string `json:"type"`
}
type DBAccessor interface {
Migrate() error
//Generic map objects (poi, etc)
GetMapData(q SearchQuery) ([]MapObject, error)
GetMapData(q SearchQuery) ([]*MapObject, error)
RemoveMapData(pos *coords.MapBlockCoords) error
AddMapData(data *MapObject) error

View File

@ -4,8 +4,72 @@ import (
"mapserver/coords"
)
func (db *Sqlite3Accessor) GetMapData(q SearchQuery) ([]MapObject, error) {
return nil, nil
const getMapDataPosQuery = `
select o.id, o.type, o.mtime,
o.x, o.y, o.z,
o.posx, o.posy, o.posz,
oa.key, oa.value
from objects o
left join object_attributes oa on o.id = oa.objectid
where o.type = ?
and o.posx >= ? and o.posy >= ? and o.posz >= ?
and o.posx <= ? and o.posy <= ? and o.posz <= ?
order by o.id
`
func (db *Sqlite3Accessor) GetMapData(q SearchQuery) ([]*MapObject, error) {
rows, err := db.db.Query(getMapDataPosQuery,
q.Type,
q.Pos1.X, q.Pos1.Y, q.Pos1.Z,
q.Pos2.X, q.Pos2.Y, q.Pos2.Z,
)
if err != nil {
return nil, err
}
defer rows.Close()
result := make([]*MapObject, 0)
var currentObj *MapObject
var currentId *int64
for rows.Next() {
var id int64
var Type string
var mtime int64
var x, y, z int
var posx, posy, posz int
var key, value string
err = rows.Scan(&id, &Type, &mtime,
&x, &y, &z, &posx, &posy, &posz,
&key, &value,
)
if err != nil {
return nil, err
}
if currentId == nil || *currentId != id {
pos := coords.NewMapBlockCoords(posx, posy, posz)
mo := NewMapObject(
&pos,
x, y, z,
Type,
)
currentObj = mo
currentId = &id
result = append(result, currentObj)
}
currentObj.Attributes[key] = value
}
return result, nil
}
const removeMapDataQuery = `

View File

@ -0,0 +1,19 @@
package mapobjectdb
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
)
func NewSqliteAccessor(filename string) (*Sqlite3Accessor, error) {
//TODO: flag/config for unsafe db access
db, err := sql.Open("sqlite3", filename+"?_timeout=500&_journal_mode=MEMORY&_synchronous=OFF")
db.SetMaxOpenConns(1)
if err != nil {
return nil, err
}
sq := &Sqlite3Accessor{db: db, filename: filename}
return sq, nil
}

View File

@ -1,6 +1,7 @@
package mapobjectdb
import (
"fmt"
"io/ioutil"
"mapserver/coords"
"os"
@ -101,4 +102,20 @@ func TestMapObjects(t *testing.T) {
panic(err)
}
q := SearchQuery{
Pos1: pos,
Pos2: pos,
Type: "xy",
}
objs, err := db.GetMapData(q)
if err != nil {
panic(err)
}
for _, mo := range objs {
fmt.Println(mo)
}
}

View File

@ -1,8 +1,6 @@
package mapobjectdb
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"mapserver/coords"
)
@ -66,16 +64,3 @@ func (db *Sqlite3Accessor) RemoveTile(pos *coords.TileCoords) error {
_, err := db.db.Exec(removeTileQuery, pos.X, pos.Y, pos.Zoom, pos.LayerId)
return err
}
func NewSqliteAccessor(filename string) (*Sqlite3Accessor, error) {
//TODO: flag/config for unsafe db access
db, err := sql.Open("sqlite3", filename+"?_timeout=500&_journal_mode=MEMORY&_synchronous=OFF")
db.SetMaxOpenConns(1)
if err != nil {
return nil, err
}
sq := &Sqlite3Accessor{db: db, filename: filename}
return sq, nil
}

View File

@ -0,0 +1,14 @@
package playerdb
type Player struct {
X int `json:"x"`
Y int `json:"y"`
Z int `json:"z"`
Name string `json:"name"`
HP int `json:"hp"`
//TODO: stamina, skin, etc
}
type DBAccessor interface {
GetActivePlayers() ([]*Player, error)
}

View File

@ -0,0 +1,34 @@
package playerdb
import (
"io/ioutil"
"time"
)
//https://stackoverflow.com/questions/46746862/list-files-in-a-directory-sorted-by-creation-time
type FilePlayerDB struct{}
func (this *FilePlayerDB) GetActivePlayers() ([]*Player, error) {
files, err := ioutil.ReadDir("Players")
if err != nil {
return nil, err
}
now := time.Now().Unix()
activeTime := now - 5
result := make([]*Player, 0)
for _, file := range files {
if file.ModTime().Unix() > activeTime {
p := Player{}
//TODO: parse
result = append(result, &p)
}
}
return result, nil
}

15
server/playerdb/create.go Normal file
View File

@ -0,0 +1,15 @@
package playerdb
import (
"errors"
"mapserver/worldconfig"
)
func Create(cfg *worldconfig.WorldConfig) (DBAccessor, error) {
switch cfg.PlayerBackend {
case worldconfig.BACKEND_FILES:
return &FilePlayerDB{}, nil
default:
return nil, errors.New("player backend not supported: " + worldconfig.BACKEND_FILES)
}
}

View File

@ -1,11 +1,12 @@
package tilerendererjob
import (
"github.com/sirupsen/logrus"
"mapserver/app"
"mapserver/coords"
"mapserver/mapblockparser"
"strconv"
"github.com/sirupsen/logrus"
)
func getTileKey(tc *coords.TileCoords) string {
@ -41,6 +42,11 @@ func renderMapblocks(ctx *app.App, jobs chan *coords.TileCoords, mblist []*mapbl
logrus.WithFields(fields).Debug("Dispatching tile rendering (z11-1)")
tilecount++
//remove tile
ctx.Objectdb.RemoveTile(tc)
//dispatch re-render
jobs <- tc
}
}

View File

@ -1,10 +1,11 @@
package tilerendererjob
import (
"github.com/sirupsen/logrus"
"mapserver/app"
"mapserver/coords"
"time"
"github.com/sirupsen/logrus"
)
func incrementalRender(ctx *app.App, jobs chan *coords.TileCoords) {
@ -25,6 +26,9 @@ func incrementalRender(ctx *app.App, jobs chan *coords.TileCoords) {
panic(err)
}
rstate.LastMtime = result.LastMtime
ctx.Config.Save()
if len(result.List) == 0 {
time.Sleep(5 * time.Second)
continue
@ -32,9 +36,6 @@ func incrementalRender(ctx *app.App, jobs chan *coords.TileCoords) {
tiles := renderMapblocks(ctx, jobs, result.List)
rstate.LastMtime = result.LastMtime
ctx.Config.Save()
t := time.Now()
elapsed := t.Sub(start)

View File

@ -20,4 +20,6 @@ func Job(ctx *app.App) {
incrementalRender(ctx, jobs)
panic("render job interrupted!")
}

View File

@ -7,8 +7,7 @@ import (
func worker(ctx *app.App, coords <-chan *coords.TileCoords) {
for tc := range coords {
ctx.Objectdb.RemoveTile(tc)
_, err := ctx.Tilerenderer.Render(tc, 2)
_, err := ctx.Tilerenderer.Render(tc, 5)
if err != nil {
panic(err)
}

View File

@ -33,11 +33,11 @@ type WorldConfig struct {
Backend string
PlayerBackend string
PsqlConnection PsqlConfig
PsqlPlayerConnection PsqlConfig
PsqlConnection *PsqlConfig
PsqlPlayerConnection *PsqlConfig
}
func parseConnectionString(str string) PsqlConfig {
func parseConnectionString(str string) *PsqlConfig {
cfg := PsqlConfig{}
pairs := strings.Split(str, " ")
@ -58,7 +58,7 @@ func parseConnectionString(str string) PsqlConfig {
}
}
return cfg
return &cfg
}
func Parse(filename string) WorldConfig {