forked from MTSR/mapserver
atom .Merge branch 'master' of github.com:thomasrudin-mt/mapserver
This commit is contained in:
commit
4f8983141e
5
.travis.yml
Normal file
5
.travis.yml
Normal file
@ -0,0 +1,5 @@
|
||||
language: go
|
||||
|
||||
|
||||
go:
|
||||
- "1.11"
|
@ -1,7 +1,7 @@
|
||||
Minetest mapserver
|
||||
=======
|
||||
|
||||
Relatime mapserver for Minetest
|
||||
Realtime mapserver for Minetest
|
||||
|
||||
# Development state
|
||||
|
||||
|
@ -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
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "0.0.1-DEV"
|
||||
Version = "0.0.1-alpha"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
38
server/eventbus/eventbus.go
Normal file
38
server/eventbus/eventbus.go
Normal 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)
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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 = `
|
||||
|
19
server/mapobjectdb/sqlite_new.go
Normal file
19
server/mapobjectdb/sqlite_new.go
Normal 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
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
14
server/playerdb/accessor.go
Normal file
14
server/playerdb/accessor.go
Normal 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)
|
||||
}
|
34
server/playerdb/backend_file.go
Normal file
34
server/playerdb/backend_file.go
Normal 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
15
server/playerdb/create.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -20,4 +20,6 @@ func Job(ctx *app.App) {
|
||||
|
||||
incrementalRender(ctx, jobs)
|
||||
|
||||
panic("render job interrupted!")
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user