forked from MTSR/mapserver
Merge branch 'master' into threejs-wip
This commit is contained in:
commit
467429ace8
19
.github/workflows/docker.yml
vendored
Normal file
19
.github/workflows/docker.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: docker
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: docker publish
|
||||
uses: elgohr/Publish-Docker-Github-Action@master
|
||||
with:
|
||||
name: minetestmapserver/mapserver
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
tag_names: true
|
||||
cache: true
|
||||
|
24
.github/workflows/go-test.yml
vendored
Normal file
24
.github/workflows/go-test.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: go-test
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.12'
|
||||
|
||||
- name: get
|
||||
run: go get github.com/mjibson/esc
|
||||
|
||||
- name: generate
|
||||
run: go generate
|
||||
|
||||
- name: test
|
||||
run: go test ./...
|
||||
|
20
.github/workflows/jshint.yml
vendored
Normal file
20
.github/workflows/jshint.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: jshint
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: apt
|
||||
run: sudo apt-get install -y nodejs npm
|
||||
|
||||
- name: jshint install
|
||||
run: sudo npm i -g jshint
|
||||
|
||||
- name: jshint run
|
||||
run: cd static/js && jshint
|
22
.github/workflows/release.yml
vendored
Normal file
22
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: build
|
||||
run: make release
|
||||
|
||||
- name: upload
|
||||
uses: skx/github-action-publish-binaries@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
args: 'output/mapserver-*'
|
14
.travis.yml
14
.travis.yml
@ -1,14 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
script:
|
||||
- go get github.com/mjibson/esc
|
||||
- go generate
|
||||
- go build
|
||||
- go test
|
15
Dockerfile
15
Dockerfile
@ -1,22 +1,17 @@
|
||||
FROM ubuntu as builder
|
||||
FROM golang:1.13-alpine as builder
|
||||
|
||||
RUN apt-get update &&\
|
||||
apt-get install -y software-properties-common git &&\
|
||||
add-apt-repository ppa:longsleep/golang-backports &&\
|
||||
apt-get update &&\
|
||||
apt-get install -y golang-go
|
||||
RUN apk --no-cache add ca-certificates gcc libc-dev nodejs npm git make
|
||||
|
||||
VOLUME /root/go
|
||||
COPY ./ /server
|
||||
RUN cd /server &&\
|
||||
go generate &&\
|
||||
go test ./... &&\
|
||||
CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static -X mapserver/app.Version=docker"
|
||||
npm install -g jshint rollup &&\
|
||||
make test jshint all
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
WORKDIR /app
|
||||
COPY --from=builder /server/mapserver /bin/mapserver
|
||||
COPY --from=builder /server/output/mapserver-linux-x86_64 /bin/mapserver
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["/bin/mapserver"]
|
||||
|
26
Makefile
26
Makefile
@ -15,9 +15,9 @@ BINARIES += $(OUT_DIR)/mapserver-windows-x86.exe
|
||||
BINARIES += $(OUT_DIR)/mapserver-windows-x86-64.exe
|
||||
BINARIES += $(OUT_DIR)/mapserver-linux-arm
|
||||
|
||||
JS_BUNDLE = static/js/bundle.js
|
||||
|
||||
all: $(STATIC_VFS)
|
||||
go build
|
||||
all: $(STATIC_VFS) $(OUT_DIR)/mapserver-linux-x86_64
|
||||
|
||||
$(OUT_DIR):
|
||||
mkdir $@
|
||||
@ -27,23 +27,25 @@ fmt:
|
||||
|
||||
test: $(OUT_DIR)
|
||||
go generate
|
||||
go build
|
||||
go vet ./...
|
||||
$(ENV) go test ./...
|
||||
|
||||
clean:
|
||||
rm -rf $(STATIC_VFS) test-output
|
||||
rm -rf $(STATIC_VFS) $(JS_BUNDLE) test-output
|
||||
rm -rf $(OUT_DIR)
|
||||
|
||||
jshint:
|
||||
jshint static/js/*.js static/js/util static/js/overlays static/js/search
|
||||
cd static/js && jshint .
|
||||
|
||||
$(STATIC_VFS):
|
||||
$(JS_BUNDLE):
|
||||
cd static/js && rollup -c rollup.config.js
|
||||
|
||||
$(STATIC_VFS): $(JS_BUNDLE)
|
||||
go generate
|
||||
|
||||
$(OUT_DIR)/mapserver-linux-x86_64: $(OUT_DIR)
|
||||
# native (linux x86_64)
|
||||
GOOS=linux GOARCH=amd64 CC=x86_64-linux-gnu-gcc $(GO_BUILD) $(GO_LDFLAGS) -o $@
|
||||
GOOS=linux GOARCH=amd64 CC=gcc $(GO_BUILD) $(GO_LDFLAGS) -o $@
|
||||
|
||||
$(OUT_DIR)/mapserver-linux-x86: $(OUT_DIR)
|
||||
# apt install gcc-8-i686-linux-gnu
|
||||
@ -63,11 +65,11 @@ $(OUT_DIR)/mapserver-linux-arm: $(OUT_DIR)
|
||||
|
||||
release: builder_image $(OUT_DIR) $(MOD_ZIP)
|
||||
# build all with the docker image
|
||||
sudo docker run --rm -it\
|
||||
-v $(shell pwd):/app\
|
||||
-v mapserver-volume:/root/go\
|
||||
-w /app\
|
||||
mapserver-builder\
|
||||
sudo docker run --rm -i \
|
||||
-v $(shell pwd):/app \
|
||||
-v mapserver-volume:/root/go \
|
||||
-w /app \
|
||||
mapserver-builder \
|
||||
make test jshint release-all VERSION=$(VERSION)
|
||||
# copy generated files to output dir
|
||||
|
||||
|
@ -86,10 +86,10 @@ func Setup(p params.ParamsType, cfg *Config) *App {
|
||||
|
||||
colorfiles := []string{
|
||||
//https://daconcepts.com/vanessa/hobbies/minetest/colors.txt
|
||||
"/colors/custom.txt",
|
||||
"/colors/vanessa.txt",
|
||||
"/colors/advtrains.txt",
|
||||
"/colors/scifi_nodes.txt",
|
||||
"/colors/custom.txt",
|
||||
}
|
||||
|
||||
for _, colorfile := range colorfiles {
|
||||
|
@ -4,6 +4,10 @@
|
||||
## Next
|
||||
|
||||
* Train overlay decluttering
|
||||
* Updated builtin colors
|
||||
* Hide travelnets and missions by pattern "(P)"
|
||||
* Added benchmark
|
||||
* Minor speed improvements
|
||||
|
||||
## 3.0.0
|
||||
|
||||
|
7
doc/get_trainlines.sh
Normal file
7
doc/get_trainlines.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
curl -X POST -k -H 'Content-Type: application/json' 'https://pandorabox.io/map/api/mapobjects/' --data '{
|
||||
"type":"train",
|
||||
"pos1":{"x":-2048,"y":-2048,"z":-2048},
|
||||
"pos2":{"x":2048,"y":2048,"z":2048}
|
||||
}' | jq
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
**Please make a backup of your world in case something goes wrong**
|
||||
|
||||
## Simple installation
|
||||
|
||||
* Download the binary from the [releases](https://github.com/minetest-tools/mapserver/releases) for your architecture and platform
|
||||
* Drop the binary into your world folder (the one with the `world.mt` and `map.sqlite` files)
|
||||
* Start the mapserver via command-line: `./mapserver` or `./mapserver.exe`
|
||||
@ -10,6 +12,36 @@
|
||||
|
||||
For additional infos (lag,time,players => active mode) on the mapserver interface you should install the [mapserver-mod](mod.md)
|
||||
|
||||
## Docker image
|
||||
|
||||
* Docker-hub: https://hub.docker.com/repository/docker/minetestmapserver/mapserver
|
||||
|
||||
Simple docker run example to run in the world-directory:
|
||||
|
||||
```
|
||||
docker run --rm --it -p 8080:8080 -v $(pwd):/minetest -w /minetest minetestmapserver/mapserver
|
||||
```
|
||||
|
||||
## Docker compose
|
||||
|
||||
Examplary `docker-compose` config:
|
||||
|
||||
```yml
|
||||
services:
|
||||
mapserver:
|
||||
image: minetesttools/mapserver
|
||||
restart: always
|
||||
networks:
|
||||
- default
|
||||
depends_on:
|
||||
- "postgres"
|
||||
volumes:
|
||||
- "./data/minetest/world:/minetest"
|
||||
working_dir: "/minetest"
|
||||
```
|
||||
|
||||
* See also: https://github.com/pandorabox-io/pandorabox.io/blob/master/docker-compose.yml
|
||||
|
||||
## Performance / Scalability
|
||||
|
||||
For small to medium setups the default values should suffice.
|
||||
|
76
doc/recommended_specs.md
Normal file
76
doc/recommended_specs.md
Normal file
@ -0,0 +1,76 @@
|
||||
|
||||
# Recommended specs
|
||||
|
||||
Recommended specs for running the mapserver
|
||||
|
||||
## Storage
|
||||
|
||||
The tiles are cached in several zoom-levels on disk.
|
||||
Storage usage depends heavily on map-size and explored areas
|
||||
but it will be in the region of several gigabytes (5 to 10 GB for "older" servers)
|
||||
|
||||
## Memory
|
||||
|
||||
Memory depedends on the amount of caching (see: [Configuration](./config.md))
|
||||
Per default there will be around 500 mapblocks cached for quicker access.
|
||||
This will be around 5 to 10 megabytes depending on the contents.
|
||||
|
||||
The recommendation is to maximize caching so the queries don't slow down the game-database.
|
||||
If you are willing to spend around 2 GB of memory set the `maxitems` to 5000 mapblocks.
|
||||
Otherwise leave the defaults and see if it has any impact.
|
||||
|
||||
Example config from `mapserver.json`:
|
||||
```json
|
||||
{
|
||||
"mapblockaccessor": {
|
||||
"expiretime": "10s",
|
||||
"purgetime": "15s",
|
||||
"maxitems": 500
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## CPU
|
||||
|
||||
The application is more CPU-bound than IO-bound.
|
||||
It will use all the configured CPU's while rendering:
|
||||
|
||||
<img src="../pics/cpu_graph.png"/>
|
||||
|
||||
It is recommended to set the `renderjobs` setting to a number of CPU's
|
||||
you can spare.
|
||||
|
||||
Per default it will set the setting to the number of cores you have,
|
||||
but it will also run on just 1 job and take a bit longer...
|
||||
|
||||
Example config from `mapserver.json`:
|
||||
```json
|
||||
{
|
||||
"renderingjobs": 2
|
||||
}
|
||||
```
|
||||
|
||||
## Database
|
||||
|
||||
The recommended database is Postgres if you have a busy server.
|
||||
SQLite will work too if the disk-access is good.
|
||||
|
||||
**Personal experience**: Don't worry about it if you have fast SSD's ;)
|
||||
|
||||
## Network
|
||||
|
||||
I don't recommend serving the map behind a slow residential internet connection.
|
||||
An upload-bandwidth from 10 MBPS upwards will do the job pretty ok though:
|
||||
|
||||
<img src="../pics/network_graph.png"/>
|
||||
|
||||
# Recap
|
||||
|
||||
If your setup looks something like this, don't worry about performance:
|
||||
|
||||
* 4+ cores
|
||||
* 8+ GB RAM
|
||||
* 20+ GB SSD
|
||||
* Postgres DB
|
||||
|
@ -10,10 +10,9 @@ RUN add-apt-repository ppa:longsleep/golang-backports &&\
|
||||
apt-get update &&\
|
||||
apt-get install -y golang-go
|
||||
|
||||
# luacheck
|
||||
RUN apt-get install -y luarocks liblua5.1-dev
|
||||
RUN luarocks install luacheck
|
||||
|
||||
# jshint
|
||||
RUN apt-get install -y nodejs npm
|
||||
RUN npm install -g jshint
|
||||
|
||||
# rollup
|
||||
RUN npm install -g rollup
|
||||
|
17
go.mod
17
go.mod
@ -1,15 +1,16 @@
|
||||
module mapserver
|
||||
|
||||
require (
|
||||
github.com/disintegration/imaging v1.5.0
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/lib/pq v1.2.0
|
||||
github.com/mattn/go-sqlite3 v1.13.0
|
||||
github.com/mjibson/esc v0.1.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/prometheus/client_golang v0.9.2
|
||||
github.com/sirupsen/logrus v1.3.0
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/prometheus/client_golang v0.9.4
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583
|
||||
golang.org/x/image v0.0.0-20190118043309-183bebdce1b2 // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
65
go.sum
65
go.sum
@ -1,54 +1,119 @@
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.5.0 h1:uYqUhwNmLU4K1FN44vhqS4TZJRAA4RhBINgbQlKyGi0=
|
||||
github.com/disintegration/imaging v1.5.0/go.mod h1:9B/deIUIrliYkyMTuXJd6OUFLcrZ2tf+3Qlwnaf/CjU=
|
||||
github.com/disintegration/imaging v1.6.1 h1:JnBbK6ECIZb1NsWIikP9pd8gIlTIRx7fuDNpU9fsxOE=
|
||||
github.com/disintegration/imaging v1.6.1/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.12.0 h1:u/x3mp++qUxvYfulZ4HKOvVO0JWhk7HtE8lWhbGz/Do=
|
||||
github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
||||
github.com/mattn/go-sqlite3 v1.13.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mjibson/esc v0.1.0 h1:5ch+murgrcwDFLOE2hwj0f7kE4xJfJhkSCAjSLY182o=
|
||||
github.com/mjibson/esc v0.1.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v0.9.4 h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A=
|
||||
github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM=
|
||||
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 h1:SZPG5w7Qxq7bMcMVl6e3Ht2X7f+AAGQdzjkbyOnNNZ8=
|
||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190118043309-183bebdce1b2 h1:FNSSV4jv1PrPsiM2iKGpqLPPgYACqh9Muav7Pollk1k=
|
||||
golang.org/x/image v0.0.0-20190118043309-183bebdce1b2/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 h1:FDfvYgoVsA7TTZSbgiqjAbfPbK47CNHdWl3h/PJtii0=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -66,7 +66,7 @@ func getNodePos(x, y, z int) int {
|
||||
}
|
||||
|
||||
func (inv *Inventory) IsEmpty() bool {
|
||||
if inv.Size == 0 || len(inv.Items) == 0 {
|
||||
if len(inv.Items) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,7 @@ func parseMetadata(mapblock *MapBlock, data []byte) (int, error) {
|
||||
}
|
||||
|
||||
currentInventory.Items = append(currentInventory.Items, &item)
|
||||
currentInventory.Size += 1
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"mapserver/colormapping"
|
||||
"mapserver/coords"
|
||||
"mapserver/mapblockaccessor"
|
||||
@ -69,7 +68,7 @@ func addColorComponent(c *color.RGBA, value int) *color.RGBA {
|
||||
R: clamp(int(c.R) + value),
|
||||
G: clamp(int(c.G) + value),
|
||||
B: clamp(int(c.B) + value),
|
||||
A: clamp(int(c.A) + value),
|
||||
A: c.A,
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +179,7 @@ func (r *MapBlockRenderer) Render(pos1, pos2 *coords.MapBlockCoords) (*image.NRG
|
||||
if neighbourMapblock != nil && err == nil {
|
||||
top = neighbourMapblock.GetNodeName(x, y, 0)
|
||||
if y < 15 {
|
||||
topAbove = neighbourMapblock.GetNodeName(x, y+1, z+0)
|
||||
topAbove = neighbourMapblock.GetNodeName(x, y+1, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,10 +208,21 @@ func (r *MapBlockRenderer) Render(pos1, pos2 *coords.MapBlockCoords) (*image.NRG
|
||||
imgX := x * IMG_SCALE
|
||||
imgY := (15 - z) * IMG_SCALE
|
||||
|
||||
rect := image.Rect(
|
||||
imgX, imgY,
|
||||
imgX+IMG_SCALE, imgY+IMG_SCALE,
|
||||
)
|
||||
r32, g32, b32, a32 := c.RGBA()
|
||||
r8, g8, b8, a8 := uint8(r32), uint8(g32), uint8(b32), uint8(a32)
|
||||
for Y := imgY; Y < imgY+IMG_SCALE; Y++ {
|
||||
ix := (Y*IMG_SIZE + imgX) << 2
|
||||
for X := 0; X < IMG_SCALE; X++ {
|
||||
img.Pix[ix] = r8
|
||||
ix++
|
||||
img.Pix[ix] = g8
|
||||
ix++
|
||||
img.Pix[ix] = b8
|
||||
ix++
|
||||
img.Pix[ix] = a8
|
||||
ix++
|
||||
}
|
||||
}
|
||||
|
||||
if c.A != 0xFF || !r.enableTransparency {
|
||||
//not transparent, mark as rendered
|
||||
@ -220,8 +230,6 @@ func (r *MapBlockRenderer) Render(pos1, pos2 *coords.MapBlockCoords) (*image.NRG
|
||||
xzOccupationMap[x][z] = true
|
||||
}
|
||||
|
||||
draw.Draw(img, rect, &image.Uniform{c}, image.ZP, draw.Src)
|
||||
|
||||
if foundBlocks == EXPECTED_BLOCKS_PER_FLAT_MAPBLOCK {
|
||||
return img, nil
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package mapobject
|
||||
import (
|
||||
"mapserver/mapblockparser"
|
||||
"mapserver/mapobjectdb"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type BonesBlock struct{}
|
||||
@ -10,13 +11,24 @@ type BonesBlock struct{}
|
||||
func (this *BonesBlock) onMapObject(x, y, z int, block *mapblockparser.MapBlock) *mapobjectdb.MapObject {
|
||||
md := block.Metadata.GetMetadata(x, y, z)
|
||||
|
||||
if md["owner"] == "" {
|
||||
invMap := block.Metadata.GetInventoryMapAtPos(x, y, z)
|
||||
mainInv := invMap["main"]
|
||||
|
||||
if mainInv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
o := mapobjectdb.NewMapObject(block.Pos, x, y, z, "bones")
|
||||
o.Attributes["time"] = md["time"]
|
||||
o.Attributes["owner"] = md["owner"]
|
||||
o.Attributes["info"] = md["infotext"]
|
||||
|
||||
itemCount := 0
|
||||
for _, item := range mainInv.Items {
|
||||
itemCount += item.Count
|
||||
}
|
||||
|
||||
o.Attributes["item_count"] = strconv.Itoa(itemCount)
|
||||
|
||||
return o
|
||||
}
|
||||
|
@ -19,16 +19,11 @@ func (this *FancyVend) onMapObject(x, y, z int, block *mapblockparser.MapBlock)
|
||||
parser := luaparser.New()
|
||||
|
||||
isAdmin := false
|
||||
isDepositor := false
|
||||
|
||||
if nodename == "fancy_vend:admin_vendor" || nodename == "fancy_vend:admin_depo" {
|
||||
isAdmin = true
|
||||
}
|
||||
|
||||
if nodename == "fancy_vend:player_depo" || nodename == "fancy_vend:admin_depo" {
|
||||
isDepositor = true
|
||||
}
|
||||
|
||||
payInv := invMap["wanted_item"]
|
||||
giveInv := invMap["given_item"]
|
||||
mainInv := invMap["main"]
|
||||
@ -93,19 +88,11 @@ func (this *FancyVend) onMapObject(x, y, z int, block *mapblockparser.MapBlock)
|
||||
o.Attributes["owner"] = md["owner"]
|
||||
o.Attributes["type"] = "fancyvend"
|
||||
|
||||
if !isDepositor {
|
||||
o.Attributes["in_item"] = in_item
|
||||
o.Attributes["in_count"] = strconv.Itoa(in_count)
|
||||
o.Attributes["out_item"] = out_item
|
||||
o.Attributes["out_count"] = strconv.Itoa(out_count)
|
||||
} else {
|
||||
// invert in and out
|
||||
o.Attributes["out_item"] = in_item
|
||||
o.Attributes["out_count"] = strconv.Itoa(in_count)
|
||||
o.Attributes["in_item"] = out_item
|
||||
o.Attributes["in_count"] = strconv.Itoa(out_count)
|
||||
o.Attributes["in_item"] = in_item
|
||||
o.Attributes["in_count"] = strconv.Itoa(in_count)
|
||||
o.Attributes["out_item"] = out_item
|
||||
o.Attributes["out_count"] = strconv.Itoa(out_count)
|
||||
|
||||
}
|
||||
o.Attributes["stock"] = strconv.Itoa(stock_factor)
|
||||
|
||||
return o
|
||||
|
@ -15,6 +15,7 @@ func (this *SmartShopBlock) onMapObject(x, y, z int, block *mapblockparser.MapBl
|
||||
md := block.Metadata.GetMetadata(x, y, z)
|
||||
invMap := block.Metadata.GetInventoryMapAtPos(x, y, z)
|
||||
mainInv := invMap["main"]
|
||||
isCreative := md["type"] == "0"
|
||||
|
||||
if mainInv.IsEmpty() {
|
||||
return list
|
||||
@ -27,7 +28,7 @@ func (this *SmartShopBlock) onMapObject(x, y, z int, block *mapblockparser.MapBl
|
||||
pay := invMap[payInvName]
|
||||
give := invMap[giveInvName]
|
||||
|
||||
if pay.IsEmpty() || give.IsEmpty() {
|
||||
if len(pay.Items) == 0 || len(give.Items) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -43,10 +44,16 @@ func (this *SmartShopBlock) onMapObject(x, y, z int, block *mapblockparser.MapBl
|
||||
|
||||
stock := 0
|
||||
|
||||
for _, item := range mainInv.Items {
|
||||
if item.Name == out_item {
|
||||
stock += item.Count
|
||||
if isCreative {
|
||||
stock = 999
|
||||
|
||||
} else {
|
||||
for _, item := range mainInv.Items {
|
||||
if item.Name == out_item {
|
||||
stock += item.Count
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//multiples of out_count
|
||||
|
BIN
pics/cpu_graph.png
Normal file
BIN
pics/cpu_graph.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
pics/network_graph.png
Normal file
BIN
pics/network_graph.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
10
readme.md
10
readme.md
@ -1,13 +1,15 @@
|
||||
Minetest mapserver
|
||||
=======
|
||||
|
||||
<img src="./doc/pics/General_map_preview.png">
|
||||
|
||||
[![Dependencies](https://img.shields.io/librariesio/github/minetest-tools/mapserver.svg)](https://github.com/minetest-tools/mapserver)
|
||||
[![Build Status](https://travis-ci.org/minetest-tools/mapserver.svg?branch=master)](https://travis-ci.org/minetest-tools/mapserver)
|
||||
![](https://github.com/minetest-mapserver/mapserver/workflows/jshint/badge.svg)
|
||||
![](https://github.com/minetest-mapserver/mapserver/workflows/go-test/badge.svg)
|
||||
|
||||
![GitHub repo size](https://img.shields.io/github/repo-size/minetest-tools/mapserver.svg)
|
||||
![GitHub closed issues](https://img.shields.io/github/issues-closed/minetest-tools/mapserver.svg)
|
||||
|
||||
<img src="./doc/pics/General_map_preview.png">
|
||||
|
||||
Realtime mapserver for [Minetest](https://minetest.net)
|
||||
|
||||
Demo: [Pandorabox Server map](https://pandorabox.io/map/#-1782.25/493.5/10)
|
||||
@ -20,6 +22,7 @@ Demo: [Pandorabox Server map](https://pandorabox.io/map/#-1782.25/493.5/10)
|
||||
* [Parameters](doc/params.md)
|
||||
* [Search](doc/search.md)
|
||||
* [Configuration](doc/config.md)
|
||||
* [Recommended specs](doc/recommended_specs.md)
|
||||
* [Contribution](doc/contrib.md)
|
||||
* [Development](doc/dev.md)
|
||||
* [License](doc/license.md)
|
||||
@ -53,6 +56,7 @@ See: [Incremental rendering](doc/incrementalrendering.md)
|
||||
## Planned Features
|
||||
|
||||
* Isometric view
|
||||
* Skin support
|
||||
* Route planning (via travelnets / trains)
|
||||
|
||||
# Supported map-databases
|
||||
|
@ -4,4 +4,13 @@ planetoidgen:sun 255 100 0
|
||||
|
||||
# beacon
|
||||
beacon:redbeam 255 0 0
|
||||
beacon:greenbeam 0 255 0
|
||||
beacon:greenbeam 0 255 0
|
||||
|
||||
# ores (thx to MilesDyson)
|
||||
default:stone_with_coal 36 36 36
|
||||
default:stone_with_copper 115 113 66
|
||||
default:stone_with_diamond 108 255 255
|
||||
default:stone_with_gold 255 228 0
|
||||
default:stone_with_iron 146 73 36
|
||||
default:stone_with_mese 186 194 0
|
||||
default:stone_with_tin 202 202 202
|
||||
|
@ -1,14 +1,15 @@
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#image-map {
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.full-screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #ccc;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.leaflet-custom-display {
|
||||
@ -16,15 +17,6 @@ body {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#search-menu {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
bottom: 5%;
|
||||
left: 5%;
|
||||
right: 5%;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.mapserver-label-icon {
|
||||
margin-left: -100px !important;
|
||||
margin-top: -100px !important;
|
||||
|
@ -15,8 +15,10 @@
|
||||
<title>Minetest Mapserver</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="image-map"></div>
|
||||
<div id="search-content"></div>
|
||||
<div id="app">
|
||||
<br>
|
||||
<h5 style="text-align: center;">Starting mapserver...</h5>
|
||||
</div>
|
||||
|
||||
<!-- libraries -->
|
||||
<script src="js/lib/mithril.min.js"></script>
|
||||
@ -25,9 +27,9 @@
|
||||
<script src="js/lib/moment.min.js"></script>
|
||||
|
||||
<!-- main module -->
|
||||
<script src="js/main.js" type="module"></script>
|
||||
<script src="js/main.js?v=1.0" type="module"></script>
|
||||
|
||||
<!-- unsupported -->
|
||||
<script src="js/nomodule.js" nomodule></script>
|
||||
<!-- no modules -->
|
||||
<script src="js/bundle.js?v=1.0" nomodule></script>
|
||||
</body>
|
||||
</html>
|
||||
|
2
static/js/.gitignore
vendored
Normal file
2
static/js/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
bundle.js
|
||||
bundle.js.map
|
2
static/js/.jshintignore
Normal file
2
static/js/.jshintignore
Normal file
@ -0,0 +1,2 @@
|
||||
bundle.js
|
||||
lib/*
|
@ -1,59 +0,0 @@
|
||||
|
||||
export default {
|
||||
|
||||
setup: function(map, layerMgr){
|
||||
function updateHash(){
|
||||
var center = map.getCenter();
|
||||
window.location.hash =
|
||||
layerMgr.getCurrentLayer().id + "/" +
|
||||
center.lng + "/" + center.lat + "/" + map.getZoom();
|
||||
}
|
||||
|
||||
map.on('zoomend', updateHash);
|
||||
map.on('moveend', updateHash);
|
||||
map.on('baselayerchange', updateHash);
|
||||
updateHash();
|
||||
},
|
||||
|
||||
getLayerId: function(){
|
||||
var hashParts = window.location.hash.substring(1).split("/");
|
||||
if (hashParts.length == 4){
|
||||
//new format
|
||||
return +hashParts[0];
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
getZoom: function(){
|
||||
var hashParts = window.location.hash.substring(1).split("/");
|
||||
if (hashParts.length == 3){
|
||||
//old format
|
||||
return +hashParts[2];
|
||||
|
||||
} else if (hashParts.length == 4){
|
||||
//new format
|
||||
return +hashParts[3];
|
||||
|
||||
}
|
||||
|
||||
return 11;
|
||||
},
|
||||
|
||||
getCenter: function(){
|
||||
var hashParts = window.location.hash.substring(1).split("/");
|
||||
if (hashParts.length == 3){
|
||||
//old format
|
||||
return [+hashParts[1], +hashParts[0]];
|
||||
|
||||
} else if (hashParts.length == 4){
|
||||
//new format
|
||||
return [+hashParts[2], +hashParts[1]];
|
||||
|
||||
}
|
||||
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
};
|
@ -1,46 +1,9 @@
|
||||
import RealtimeTileLayer from './RealtimeTileLayer.js';
|
||||
|
||||
class LayerManager {
|
||||
|
||||
setup(wsChannel, layers, map, currentLayerId){
|
||||
this.listeners = [];
|
||||
this.currentLayer = layers[0];
|
||||
setup(layers){
|
||||
this.layers = layers;
|
||||
this.map = map;
|
||||
this.layerObjects = {};
|
||||
|
||||
var self = this;
|
||||
|
||||
//All layers
|
||||
layers.forEach(function(layer){
|
||||
var tileLayer = new RealtimeTileLayer(wsChannel, layer.id, map);
|
||||
self.layerObjects[layer.name] = tileLayer;
|
||||
if (layer.id == currentLayerId){
|
||||
tileLayer.addTo(map);
|
||||
self.currentLayer = layer;
|
||||
}
|
||||
});
|
||||
|
||||
map.on('baselayerchange', function (e) {
|
||||
self.setLayerId(e.layer.layerId);
|
||||
});
|
||||
}
|
||||
|
||||
switchLayer(layerId){
|
||||
var self = this;
|
||||
Object.keys(this.layerObjects).forEach(function(key){
|
||||
var layerObj = self.layerObjects[key];
|
||||
if (self.map.hasLayer(layerObj)){
|
||||
self.map.removeLayer(layerObj);
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(this.layerObjects).forEach(function(key){
|
||||
var layerObj = self.layerObjects[key];
|
||||
if (layerObj.layerId == layerId){
|
||||
self.map.addLayer(layerObj);
|
||||
}
|
||||
});
|
||||
this.currentLayer = this.layers[0];
|
||||
}
|
||||
|
||||
setLayerId(layerId){
|
||||
@ -48,28 +11,20 @@ class LayerManager {
|
||||
this.layers.forEach(function(layer){
|
||||
if (layer.id == layerId){
|
||||
self.currentLayer = layer;
|
||||
self.listeners.forEach(function(listener){
|
||||
listener(layer);
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (layerId != this.currentLayer.id){
|
||||
// layer not found
|
||||
this.currentLayer = this.layers[0];
|
||||
}
|
||||
}
|
||||
|
||||
getLayerByY(y){
|
||||
return this.layers.find(layer => (y >= (layer.from*16) && y <= (layer.to*16)));
|
||||
}
|
||||
|
||||
addListener(listener){
|
||||
this.listeners.push(listener);
|
||||
}
|
||||
|
||||
removeListener(listener){
|
||||
this.listeners = this.listeners.filter(function(el){
|
||||
return el != listener;
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentLayer(){
|
||||
return this.currentLayer;
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
import SearchMenu from './search/SearchMenu.js';
|
||||
import SearchInput from './search/SearchInput.js';
|
||||
|
||||
export default L.Control.extend({
|
||||
initialize: function(wsChannel, opts) {
|
||||
L.Control.prototype.initialize.call(this, opts);
|
||||
},
|
||||
|
||||
onAdd: function(map) {
|
||||
var div = L.DomUtil.create('div');
|
||||
m.mount(div, SearchInput);
|
||||
m.mount(document.getElementById("search-content"), {
|
||||
view: () => m(SearchMenu, {map: map})
|
||||
});
|
||||
|
||||
return div;
|
||||
}
|
||||
});
|
33
static/js/compat.js
Normal file
33
static/js/compat.js
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
export function hashCompat(){
|
||||
|
||||
if (window.location.hash) {
|
||||
|
||||
const parts = window.location.hash.replace("#", "").split("/");
|
||||
if (parts.length == 0){
|
||||
//invalid
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts[0] == "map"){
|
||||
//new link
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(+parts[0])){
|
||||
//NaN
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts.length == 3){
|
||||
// #1799.5/399/10
|
||||
window.location.hash = `#!/map/0/${parts[2]}/${parts[0]}/${parts[1]}`;
|
||||
}
|
||||
|
||||
if (parts.length == 4) {
|
||||
// #0/-1799.5/399/10
|
||||
// #0/5405.875/11148/12
|
||||
window.location.hash = `#!/map/${parts[0]}/${parts[3]}/${parts[1]}/${parts[2]}`;
|
||||
}
|
||||
}
|
||||
}
|
22
static/js/components/LayerSelector.js
Normal file
22
static/js/components/LayerSelector.js
Normal file
@ -0,0 +1,22 @@
|
||||
import LayerManager from '../LayerManager.js';
|
||||
|
||||
function onchange(e){
|
||||
const params = m.route.param();
|
||||
params.layerId = e.target.value;
|
||||
|
||||
m.route.set("/map/:layerId/:zoom/:lon/:lat", params);
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
view: function(){
|
||||
|
||||
const layers = LayerManager.layers.map(layer => m(
|
||||
"option",
|
||||
{ value: layer.id, selected: layer.id == LayerManager.getCurrentLayer().id },
|
||||
layer.name
|
||||
));
|
||||
|
||||
return m("select", { class: "form-control", onchange: onchange },layers);
|
||||
}
|
||||
};
|
61
static/js/components/Map.js
Normal file
61
static/js/components/Map.js
Normal file
@ -0,0 +1,61 @@
|
||||
import layerManager from '../LayerManager.js';
|
||||
import { createMap } from '../map/MapFactory.js';
|
||||
|
||||
function setupMap(vnode, id){
|
||||
const map = createMap(
|
||||
id,
|
||||
layerManager.getCurrentLayer().id,
|
||||
+vnode.attrs.zoom,
|
||||
+vnode.attrs.lat,
|
||||
+vnode.attrs.lon
|
||||
);
|
||||
|
||||
vnode.state.map = map;
|
||||
|
||||
function updateHash(){
|
||||
const center = map.getCenter();
|
||||
const layerId = layerManager.getCurrentLayer().id;
|
||||
|
||||
m.route.set(`/map/${layerId}/${map.getZoom()}/` +
|
||||
`${Math.floor(center.lng)}/${Math.floor(center.lat)}`);
|
||||
}
|
||||
|
||||
map.on('zoomend', updateHash);
|
||||
map.on('moveend', updateHash);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
oninit(){
|
||||
this.id = "map_" + Math.floor(Math.random() * 10000);
|
||||
},
|
||||
|
||||
view(){
|
||||
return m("div", { class: "full-screen", id: this.id });
|
||||
},
|
||||
|
||||
oncreate(vnode){
|
||||
this.map = setupMap(vnode, this.id);
|
||||
},
|
||||
|
||||
onupdate(vnode){
|
||||
if (vnode.attrs.layerId != layerManager.getCurrentLayer().id){
|
||||
//layer changed, recreate map
|
||||
this.map.remove();
|
||||
layerManager.setLayerId(vnode.attrs.layerId);
|
||||
this.map = setupMap(vnode, this.id);
|
||||
|
||||
} else {
|
||||
//position/zoom change
|
||||
//this.map.setView([+vnode.attrs.lat, +vnode.attrs.lon], +vnode.attrs.zoom);
|
||||
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
onremove(){
|
||||
this.map.remove();
|
||||
}
|
||||
};
|
62
static/js/components/Search.js
Normal file
62
static/js/components/Search.js
Normal file
@ -0,0 +1,62 @@
|
||||
import SearchResult from './SearchResult.js';
|
||||
import { getMapObjects } from '../api.js';
|
||||
|
||||
const state = {
|
||||
busy: false,
|
||||
result: []
|
||||
};
|
||||
|
||||
function searchFor(type, key, valuelike){
|
||||
return getMapObjects({
|
||||
pos1: { x:-2048, y:-2048, z:-2048 },
|
||||
pos2: { x:2048, y:2048, z:2048 },
|
||||
type: type,
|
||||
attributelike: {
|
||||
key: key,
|
||||
value: "%" + valuelike +"%"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function search(query){
|
||||
state.result = [];
|
||||
|
||||
var prom_list = [
|
||||
searchFor("shop", "out_item", query),
|
||||
searchFor("poi", "name", query),
|
||||
searchFor("train", "station", query),
|
||||
searchFor("travelnet", "station_name", query),
|
||||
searchFor("bones", "owner", query),
|
||||
searchFor("locator", "name", query),
|
||||
searchFor("label", "text", query),
|
||||
searchFor("digiterm", "display_text", query),
|
||||
searchFor("digilinelcd", "text", query)
|
||||
];
|
||||
|
||||
Promise.all(prom_list)
|
||||
.then(function(results){
|
||||
|
||||
var arr = [];
|
||||
results.forEach(function(r) {
|
||||
arr = arr.concat(r);
|
||||
});
|
||||
|
||||
state.result = arr;
|
||||
state.busy = false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
oncreate(vnode){
|
||||
search(vnode.attrs.query);
|
||||
},
|
||||
|
||||
view(vnode){
|
||||
if (state.result.length == 0) {
|
||||
return m("div", vnode.attrs.query);
|
||||
} else {
|
||||
return m(SearchResult, { result: state.result });
|
||||
}
|
||||
}
|
||||
};
|
@ -1,31 +1,34 @@
|
||||
import SearchStore from './SearchStore.js';
|
||||
import SearchService from './SearchService.js';
|
||||
|
||||
const state = {
|
||||
query: ""
|
||||
};
|
||||
|
||||
function doSearch(){
|
||||
m.route.set(`/search/${state.query}`);
|
||||
}
|
||||
|
||||
export default {
|
||||
view: function(){
|
||||
|
||||
function handleInput(e){
|
||||
SearchStore.query = e.target.value;
|
||||
state.query = e.target.value;
|
||||
}
|
||||
|
||||
function handleKeyDown(e){
|
||||
if (e.keyCode == 13){
|
||||
SearchService.search();
|
||||
doSearch();
|
||||
}
|
||||
}
|
||||
|
||||
function handleDoSearch(){
|
||||
SearchService.search();
|
||||
}
|
||||
|
||||
return m("div", { class: "input-group mb-3" }, [
|
||||
m("input[type=text]", {
|
||||
placeholder: "Search",
|
||||
class: "form-control",
|
||||
oninput: handleInput,
|
||||
onkeydown: handleKeyDown,
|
||||
value: SearchStore.query
|
||||
value: state.query
|
||||
}),
|
||||
m("div", { class: "input-group-append", onclick: handleDoSearch }, [
|
||||
m("div", { class: "input-group-append", onclick: doSearch }, [
|
||||
m("span", { class: "input-group-text" }, [
|
||||
m("i", { class: "fa fa-search"})
|
||||
])
|
@ -1,9 +1,8 @@
|
||||
import SearchStore from './SearchStore.js';
|
||||
import layerMgr from '../LayerManager.js';
|
||||
|
||||
export default {
|
||||
view: function(vnode){
|
||||
var map = vnode.attrs.map;
|
||||
var result = vnode.attrs.result;
|
||||
|
||||
function getLayer(obj){
|
||||
var layer = layerMgr.getLayerByY(obj.y);
|
||||
@ -16,7 +15,7 @@ export default {
|
||||
return m("span", {class:"badge badge-success"}, text);
|
||||
}
|
||||
|
||||
var rows = SearchStore.result.map(function(obj){
|
||||
var rows = result.map(function(obj){
|
||||
|
||||
var row_classes = "";
|
||||
var description = obj.type;
|
||||
@ -100,10 +99,18 @@ export default {
|
||||
|
||||
description = m("span", [
|
||||
"Shop, trading ",
|
||||
m("span", {class:"badge badge-primary"}, obj.attributes.out_count + "x"),
|
||||
m("span", {class:"badge badge-primary"},
|
||||
obj.attributes.out_count,
|
||||
"x",
|
||||
m("i", {class:"fa fa-cart-arrow-down"})
|
||||
),
|
||||
m("span", {class:"badge badge-info"}, obj.attributes.out_item),
|
||||
" for ",
|
||||
m("span", {class:"badge badge-primary"}, obj.attributes.in_count + "x"),
|
||||
m("span", {class:"badge badge-primary"},
|
||||
obj.attributes.in_count,
|
||||
"x",
|
||||
m("i", {class:"fa fa-money-bill"})
|
||||
),
|
||||
m("span", {class:"badge badge-info"}, obj.attributes.in_item),
|
||||
" Stock: ",
|
||||
m("span", {class:"badge badge-info"}, obj.attributes.stock)
|
||||
@ -112,11 +119,7 @@ export default {
|
||||
|
||||
function onclick(){
|
||||
var layer = layerMgr.getLayerByY(obj.y);
|
||||
|
||||
layerMgr.switchLayer(layer.id);
|
||||
|
||||
map.setView([obj.z, obj.x], 12);
|
||||
SearchStore.show = false;
|
||||
m.route.set(`/map/${layer.id}/${12}/${obj.x}/${obj.z}`);
|
||||
}
|
||||
|
||||
return m("tr", {"class": row_classes}, [
|
12
static/js/config.js
Normal file
12
static/js/config.js
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
var config;
|
||||
|
||||
export default {
|
||||
get(){
|
||||
return config;
|
||||
},
|
||||
|
||||
set(cfg){
|
||||
config = cfg;
|
||||
}
|
||||
};
|
@ -1,5 +1,21 @@
|
||||
|
||||
import { getConfig } from './api.js';
|
||||
import { setup } from './map.js';
|
||||
import routes from './routes.js';
|
||||
import wsChannel from './WebSocketChannel.js';
|
||||
import config from './config.js';
|
||||
import { hashCompat } from './compat.js';
|
||||
import layerManager from './LayerManager.js';
|
||||
|
||||
getConfig().then(setup);
|
||||
// hash route compat
|
||||
hashCompat();
|
||||
|
||||
getConfig()
|
||||
.then(cfg => {
|
||||
layerManager.setup(cfg.layers);
|
||||
config.set(cfg);
|
||||
wsChannel.connect();
|
||||
m.route(document.getElementById("app"), "/map/0/12/0/0", routes);
|
||||
})
|
||||
.catch(e => {
|
||||
document.getElementById("app").innerHTML = e;
|
||||
});
|
||||
|
@ -1,42 +0,0 @@
|
||||
import wsChannel from './WebSocketChannel.js';
|
||||
import Hashroute from './Hashroute.js';
|
||||
import SimpleCRS from './SimpleCRS.js';
|
||||
import CoordinatesDisplay from './CoordinatesDisplay.js';
|
||||
import WorldInfoDisplay from './WorldInfoDisplay.js';
|
||||
import SearchControl from './SearchControl.js';
|
||||
import Overlaysetup from './Overlaysetup.js';
|
||||
import layerManager from './LayerManager.js';
|
||||
|
||||
export function setup(cfg){
|
||||
|
||||
wsChannel.connect();
|
||||
|
||||
var map = L.map('image-map', {
|
||||
minZoom: 2,
|
||||
maxZoom: 12,
|
||||
center: Hashroute.getCenter(),
|
||||
zoom: Hashroute.getZoom(),
|
||||
crs: SimpleCRS
|
||||
});
|
||||
|
||||
map.attributionControl.addAttribution('<a href="https://github.com/minetest-tools/mapserver">Minetest Mapserver</a>');
|
||||
|
||||
var overlays = {};
|
||||
|
||||
layerManager.setup(wsChannel, cfg.layers, map, Hashroute.getLayerId());
|
||||
|
||||
//All overlays
|
||||
Overlaysetup(cfg, map, overlays, wsChannel, layerManager);
|
||||
|
||||
new CoordinatesDisplay({ position: 'bottomleft' }).addTo(map);
|
||||
new WorldInfoDisplay(wsChannel, { position: 'bottomright' }).addTo(map);
|
||||
|
||||
if (cfg.enablesearch){
|
||||
new SearchControl(wsChannel, { position: 'topright' }).addTo(map);
|
||||
}
|
||||
|
||||
//layer control
|
||||
L.control.layers(layerManager.layerObjects, overlays, { position: "topright" }).addTo(map);
|
||||
|
||||
Hashroute.setup(map, layerManager);
|
||||
}
|
48
static/js/map/CustomOverlay.js
Normal file
48
static/js/map/CustomOverlay.js
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
var customOverlays = {};
|
||||
|
||||
try {
|
||||
customOverlays = JSON.parse(localStorage["mapserver-customOverlays"]);
|
||||
} catch (e){}
|
||||
|
||||
function save(){
|
||||
localStorage["mapserver-customOverlays"] = JSON.stringify(customOverlays);
|
||||
}
|
||||
|
||||
function onAddLayer(e){
|
||||
customOverlays[e.name] = true;
|
||||
save();
|
||||
}
|
||||
|
||||
function onRemoveLayer(e){
|
||||
customOverlays[e.name] = false;
|
||||
save();
|
||||
}
|
||||
|
||||
export default function(map, overlays){
|
||||
|
||||
Object.keys(customOverlays)
|
||||
.filter(name => overlays[name])
|
||||
.forEach(name => {
|
||||
const layer = overlays[name];
|
||||
|
||||
if (customOverlays[name] && !map.hasLayer(layer)){
|
||||
//Add
|
||||
map.addLayer(layer);
|
||||
}
|
||||
|
||||
if (!customOverlays[name] && map.hasLayer(layer)){
|
||||
//Remove
|
||||
map.removeLayer(layer);
|
||||
}
|
||||
});
|
||||
|
||||
map.on('unload', () => {
|
||||
map.off('overlayadd', onAddLayer);
|
||||
map.off('overlayremove', onRemoveLayer);
|
||||
});
|
||||
|
||||
map.on('overlayadd', onAddLayer);
|
||||
map.on('overlayremove', onRemoveLayer);
|
||||
|
||||
}
|
43
static/js/map/MapFactory.js
Normal file
43
static/js/map/MapFactory.js
Normal file
@ -0,0 +1,43 @@
|
||||
import wsChannel from '../WebSocketChannel.js';
|
||||
import SimpleCRS from './SimpleCRS.js';
|
||||
import CoordinatesDisplay from './CoordinatesDisplay.js';
|
||||
import WorldInfoDisplay from './WorldInfoDisplay.js';
|
||||
import TopRightControl from './TopRightControl.js';
|
||||
import Overlaysetup from './Overlaysetup.js';
|
||||
import CustomOverlay from './CustomOverlay.js';
|
||||
import RealtimeTileLayer from './RealtimeTileLayer.js';
|
||||
|
||||
import config from '../config.js';
|
||||
|
||||
|
||||
export function createMap(node, layerId, zoom, lat, lon){
|
||||
|
||||
const cfg = config.get();
|
||||
|
||||
const map = L.map(node, {
|
||||
minZoom: 2,
|
||||
maxZoom: 12,
|
||||
center: [lat, lon],
|
||||
zoom: zoom,
|
||||
crs: SimpleCRS
|
||||
});
|
||||
|
||||
map.attributionControl.addAttribution('<a href="https://github.com/minetest-mapserver/mapserver">Minetest Mapserver</a>');
|
||||
|
||||
var tileLayer = new RealtimeTileLayer(wsChannel, layerId, map);
|
||||
tileLayer.addTo(map);
|
||||
|
||||
//All overlays
|
||||
var overlays = {};
|
||||
Overlaysetup(cfg, map, overlays);
|
||||
CustomOverlay(map, overlays);
|
||||
|
||||
new CoordinatesDisplay({ position: 'bottomleft' }).addTo(map);
|
||||
new WorldInfoDisplay(wsChannel, { position: 'bottomright' }).addTo(map);
|
||||
new TopRightControl({ position: 'topright' }).addTo(map);
|
||||
|
||||
//layer control
|
||||
L.control.layers({}, overlays, { position: "topright" }).addTo(map);
|
||||
|
||||
return map;
|
||||
}
|
@ -22,140 +22,140 @@ import BorderOverlay from './overlays/BorderOverlay.js';
|
||||
import TrainOverlay from './overlays/TrainOverlay.js';
|
||||
import TrainsignalOverlay from './overlays/TrainsignalOverlay.js';
|
||||
|
||||
export default function(cfg, map, overlays, wsChannel, layerMgr){
|
||||
export default function(cfg, map, overlays, wsChannel){
|
||||
|
||||
function isDefault(key){
|
||||
return cfg.defaultoverlays.indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mapserver_player) {
|
||||
overlays.Player = new PlayerOverlay(wsChannel, layerMgr);
|
||||
overlays.Player = new PlayerOverlay();
|
||||
if (isDefault("mapserver_player")) {
|
||||
map.addLayer(overlays.Player);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mapserver_poi) {
|
||||
overlays.POI = new PoiOverlay(wsChannel, layerMgr);
|
||||
overlays.POI = new PoiOverlay(wsChannel);
|
||||
if (isDefault("mapserver_poi")) {
|
||||
map.addLayer(overlays.POI);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.smartshop || cfg.mapobjects.fancyvend) {
|
||||
overlays.Shop = new ShopOverlay(wsChannel, layerMgr);
|
||||
overlays.Shop = new ShopOverlay();
|
||||
if (isDefault("smartshop") || isDefault("fancyvend")) {
|
||||
map.addLayer(overlays.Shop);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mapserver_label) {
|
||||
overlays.Label = new LabelOverlay(wsChannel, layerMgr);
|
||||
overlays.Label = new LabelOverlay();
|
||||
if (isDefault("mapserver_label")) {
|
||||
map.addLayer(overlays.Label);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mapserver_trainline) {
|
||||
overlays.Trainlines = new TrainlineOverlay(wsChannel, layerMgr);
|
||||
overlays.Trainlines = new TrainlineOverlay();
|
||||
if (isDefault("mapserver_trainline")) {
|
||||
map.addLayer(overlays.Trainlines);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mapserver_border) {
|
||||
overlays.Border = new BorderOverlay(wsChannel, layerMgr);
|
||||
overlays.Border = new BorderOverlay();
|
||||
if (isDefault("mapserver_border")) {
|
||||
map.addLayer(overlays.Border);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.travelnet) {
|
||||
overlays.Travelnet = new TravelnetOverlay(wsChannel, layerMgr);
|
||||
overlays.Travelnet = new TravelnetOverlay();
|
||||
if (isDefault("travelnet")) {
|
||||
map.addLayer(overlays.Travelnet);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.bones) {
|
||||
overlays.Bones = new BonesOverlay(wsChannel, layerMgr);
|
||||
overlays.Bones = new BonesOverlay();
|
||||
if (isDefault("bones")) {
|
||||
map.addLayer(overlays.Bones);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.digilines) {
|
||||
overlays["Digilines LCD"] = new LcdOverlay(wsChannel, layerMgr);
|
||||
overlays["Digilines LCD"] = new LcdOverlay();
|
||||
if (isDefault("digilines")) {
|
||||
map.addLayer(overlays["Digilines LCD"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.digiterms) {
|
||||
overlays.Digiterms = new DigitermOverlay(wsChannel, layerMgr);
|
||||
overlays.Digiterms = new DigitermOverlay();
|
||||
if (isDefault("digiterms")) {
|
||||
map.addLayer(overlays.Digiterms);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.luacontroller) {
|
||||
overlays["Lua Controller"] = new LuacontrollerOverlay(wsChannel, layerMgr);
|
||||
overlays["Lua Controller"] = new LuacontrollerOverlay();
|
||||
if (isDefault("luacontroller")) {
|
||||
map.addLayer(overlays["Lua Controller"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.technic_anchor) {
|
||||
overlays["Technic Anchor"] = new TechnicAnchorOverlay(wsChannel, layerMgr);
|
||||
overlays["Technic Anchor"] = new TechnicAnchorOverlay();
|
||||
if (isDefault("technic_anchor")) {
|
||||
map.addLayer(overlays["Technic Anchor"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.technic_quarry) {
|
||||
overlays["Technic Quarry"] = new TechnicQuarryOverlay(wsChannel, layerMgr);
|
||||
overlays["Technic Quarry"] = new TechnicQuarryOverlay();
|
||||
if (isDefault("technic_quarry")) {
|
||||
map.addLayer(overlays["Technic Quarry"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.technic_switch) {
|
||||
overlays["Technic Switching station"] = new TechnicSwitchOverlay(wsChannel, layerMgr);
|
||||
overlays["Technic Switching station"] = new TechnicSwitchOverlay();
|
||||
if (isDefault("technic_switch")) {
|
||||
map.addLayer(overlays["Technic Switching station"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.protector) {
|
||||
overlays.Protector = new ProtectorOverlay(wsChannel, layerMgr);
|
||||
overlays.Protector = new ProtectorOverlay();
|
||||
if (isDefault("protector")) {
|
||||
map.addLayer(overlays.Protector);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.xpprotector) {
|
||||
overlays["XP Protector"] = new XPProtectorOverlay(wsChannel, layerMgr);
|
||||
overlays["XP Protector"] = new XPProtectorOverlay();
|
||||
if (isDefault("xpprotector")) {
|
||||
map.addLayer(overlays["XP Protector"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.privprotector) {
|
||||
overlays["Priv Protector"] = new PrivProtectorOverlay(wsChannel, layerMgr);
|
||||
overlays["Priv Protector"] = new PrivProtectorOverlay();
|
||||
if (isDefault("privprotector")) {
|
||||
map.addLayer(overlays["Priv Protector"]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mission) {
|
||||
overlays.Missions = new MissionOverlay(wsChannel, layerMgr);
|
||||
overlays.Missions = new MissionOverlay();
|
||||
if (isDefault("mission")) {
|
||||
map.addLayer(overlays.Missions);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.train) {
|
||||
overlays.Trains = new TrainOverlay(wsChannel, layerMgr);
|
||||
overlays.Trains = new TrainOverlay();
|
||||
|
||||
if (isDefault("train")) {
|
||||
map.addLayer(overlays.Trains);
|
||||
@ -163,7 +163,7 @@ export default function(cfg, map, overlays, wsChannel, layerMgr){
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.trainsignal) {
|
||||
overlays.Trainsignals = new TrainsignalOverlay(wsChannel, layerMgr);
|
||||
overlays.Trainsignals = new TrainsignalOverlay();
|
||||
|
||||
if (isDefault("trainsignal")) {
|
||||
map.addLayer(overlays.Trainsignals);
|
||||
@ -171,21 +171,21 @@ export default function(cfg, map, overlays, wsChannel, layerMgr){
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.minecart) {
|
||||
overlays.Minecart = new MinecartOverlay(wsChannel, layerMgr);
|
||||
overlays.Minecart = new MinecartOverlay();
|
||||
if (isDefault("minecart")) {
|
||||
map.addLayer(overlays.Minecart);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.atm) {
|
||||
overlays.ATM = new ATMOverlay(wsChannel, layerMgr);
|
||||
overlays.ATM = new ATMOverlay();
|
||||
if (isDefault("atm")) {
|
||||
map.addLayer(overlays.ATM);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.locator) {
|
||||
overlays.Locator = new LocatorOverlay(wsChannel, layerMgr);
|
||||
overlays.Locator = new LocatorOverlay();
|
||||
if (isDefault("locator")) {
|
||||
map.addLayer(overlays.Locator);
|
||||
}
|
27
static/js/map/TopRightControl.js
Normal file
27
static/js/map/TopRightControl.js
Normal file
@ -0,0 +1,27 @@
|
||||
import SearchInput from '../components/SearchInput.js';
|
||||
import LayerSelector from '../components/LayerSelector.js';
|
||||
import config from '../config.js';
|
||||
|
||||
const Component = {
|
||||
view: function(){
|
||||
const cfg = config.get();
|
||||
|
||||
return m("div", [
|
||||
cfg.enablesearch ? m(SearchInput) : null,
|
||||
m(LayerSelector)
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default L.Control.extend({
|
||||
initialize: function(wsChannel, opts) {
|
||||
L.Control.prototype.initialize.call(this, opts);
|
||||
},
|
||||
|
||||
onAdd: function() {
|
||||
var div = L.DomUtil.create('div');
|
||||
m.mount(div, Component);
|
||||
return div;
|
||||
}
|
||||
});
|
@ -1,8 +1,8 @@
|
||||
import AbstractIconOverlay from './AbstractIconOverlay.js';
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "atm");
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "atm");
|
||||
},
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
@ -1,21 +1,16 @@
|
||||
import debounce from '../util/debounce.js';
|
||||
import { getMapObjects } from '../api.js';
|
||||
import debounce from '../../util/debounce.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
import { getMapObjects } from '../../api.js';
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function(wsChannel, layerMgr, type) {
|
||||
initialize: function(type) {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.layerMgr = layerMgr;
|
||||
this.wsChannel = wsChannel;
|
||||
this.type = type;
|
||||
|
||||
this.onLayerChange = this.onLayerChange.bind(this);
|
||||
this.onMapMove = debounce(this.onMapMove.bind(this), 50);
|
||||
},
|
||||
|
||||
onLayerChange: function(){
|
||||
this.reDraw();
|
||||
},
|
||||
|
||||
onMapMove: function(){
|
||||
this.reDraw();
|
||||
@ -61,7 +56,7 @@ export default L.LayerGroup.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
var min = this._map.getBounds().getSouthWest();
|
||||
var max = this._map.getBounds().getNorthEast();
|
||||
|
||||
@ -90,7 +85,6 @@ export default L.LayerGroup.extend({
|
||||
this.map = map;
|
||||
map.on("zoomend", this.onMapMove);
|
||||
map.on("moveend", this.onMapMove);
|
||||
this.layerMgr.addListener(this.onLayerChange);
|
||||
this.reDraw(true);
|
||||
},
|
||||
|
||||
@ -98,7 +92,6 @@ export default L.LayerGroup.extend({
|
||||
this.clearLayers();
|
||||
map.off("zoomend", this.onMapMove);
|
||||
map.off("moveend", this.onMapMove);
|
||||
this.layerMgr.removeListener(this.onLayerChange);
|
||||
}
|
||||
|
||||
});
|
@ -1,12 +1,13 @@
|
||||
import debounce from '../util/debounce.js';
|
||||
import { getMapObjects } from '../api.js';
|
||||
import debounce from '../../util/debounce.js';
|
||||
import wsChannel from '../../WebSocketChannel.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
import { getMapObjects } from '../../api.js';
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function(wsChannel, layerMgr, type, icon) {
|
||||
initialize: function(type, icon) {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.layerMgr = layerMgr;
|
||||
this.wsChannel = wsChannel;
|
||||
this.type = type;
|
||||
this.icon = icon;
|
||||
|
||||
@ -66,7 +67,7 @@ export default L.LayerGroup.extend({
|
||||
this.currentObjects = {};
|
||||
}
|
||||
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
var min = this.map.getBounds().getSouthWest();
|
||||
var max = this.map.getBounds().getNorthEast();
|
||||
|
||||
@ -134,8 +135,7 @@ export default L.LayerGroup.extend({
|
||||
this.map = map;
|
||||
map.on("zoomend", this.onMapMove);
|
||||
map.on("moveend", this.onMapMove);
|
||||
this.layerMgr.addListener(this.onLayerChange);
|
||||
this.wsChannel.addListener("mapobject-created", this.onMapObjectUpdated);
|
||||
wsChannel.addListener("mapobject-created", this.onMapObjectUpdated);
|
||||
this.reDraw(true);
|
||||
},
|
||||
|
||||
@ -143,8 +143,7 @@ export default L.LayerGroup.extend({
|
||||
this.clearLayers();
|
||||
map.off("zoomend", this.onMapMove);
|
||||
map.off("moveend", this.onMapMove);
|
||||
this.layerMgr.removeListener(this.onLayerChange);
|
||||
this.wsChannel.removeListener("mapobject-created", this.onMapObjectUpdated);
|
||||
wsChannel.removeListener("mapobject-created", this.onMapObjectUpdated);
|
||||
}
|
||||
|
||||
});
|
@ -9,8 +9,8 @@ var BonesIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "bones", BonesIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "bones", BonesIcon);
|
||||
},
|
||||
|
||||
createPopup: function(bones){
|
@ -1,8 +1,8 @@
|
||||
import AbstractGeoJsonOverlay from './AbstractGeoJsonOverlay.js';
|
||||
|
||||
export default AbstractGeoJsonOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "border");
|
||||
initialize: function() {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, "border");
|
||||
},
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
@ -9,8 +9,8 @@ var DigitermIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "digiterm", DigitermIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "digiterm", DigitermIcon);
|
||||
},
|
||||
|
||||
createPopup: function(lcd){
|
@ -1,8 +1,8 @@
|
||||
import AbstractIconOverlay from './AbstractIconOverlay.js';
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "label");
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "label");
|
||||
},
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
||||
@ -21,7 +21,7 @@ export default AbstractIconOverlay.extend({
|
||||
var notVisible = (fontSize < 2 || fontSize > 50);
|
||||
|
||||
const html = `
|
||||
<svg height='${height}' width='${width}' text-anchor='middle'>
|
||||
<svg height='${height}' width='${width}' text-anchor='middle' style='pointer-events: none;'>
|
||||
<text x='${width/2}' y='${height/2}'
|
||||
font-size='${fontSize}px'
|
||||
fill='${lbl.attributes.color}'
|
@ -9,8 +9,8 @@ var LcdIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "digilinelcd", LcdIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "digilinelcd", LcdIcon);
|
||||
},
|
||||
|
||||
createPopup: function(lcd){
|
@ -1,8 +1,8 @@
|
||||
import AbstractIconOverlay from './AbstractIconOverlay.js';
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "locator");
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "locator");
|
||||
},
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
@ -17,8 +17,8 @@ var LuacontrollerBurntIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "luacontroller");
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "luacontroller");
|
||||
},
|
||||
|
||||
getIcon: function(ctrl){
|
@ -1,21 +1,22 @@
|
||||
import wsChannel from '../../WebSocketChannel.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
let minecarts = [];
|
||||
|
||||
//update minecarts all the time
|
||||
wsChannel.addListener("minetest-info", function(info){
|
||||
minecarts = info.minecarts || [];
|
||||
});
|
||||
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
initialize: function() {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.layerMgr = layerMgr;
|
||||
this.wsChannel = wsChannel;
|
||||
|
||||
this.currentObjects = {}; // name => marker
|
||||
this.minecarts = [];
|
||||
|
||||
this.reDraw = this.reDraw.bind(this);
|
||||
this.onMinetestUpdate = this.onMinetestUpdate.bind(this);
|
||||
|
||||
//update players all the time
|
||||
this.wsChannel.addListener("minetest-info", function(info){
|
||||
this.minecarts = info.minecarts || [];
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
createMarker: function(cart){
|
||||
@ -38,7 +39,7 @@ export default L.LayerGroup.extend({
|
||||
},
|
||||
|
||||
isCartInCurrentLayer: function(cart){
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
return (cart.pos.y >= (mapLayer.from*16) && cart.pos.y <= (mapLayer.to*16));
|
||||
},
|
||||
@ -47,7 +48,7 @@ export default L.LayerGroup.extend({
|
||||
onMinetestUpdate: function(/*info*/){
|
||||
var self = this;
|
||||
|
||||
this.minecarts.forEach(function(cart){
|
||||
minecarts.forEach(function(cart){
|
||||
var isInLayer = self.isCartInCurrentLayer(cart);
|
||||
|
||||
if (!isInLayer){
|
||||
@ -76,7 +77,7 @@ export default L.LayerGroup.extend({
|
||||
});
|
||||
|
||||
Object.keys(self.currentObjects).forEach(function(existingId){
|
||||
var cartIsActive = self.minecarts.find(function(t){
|
||||
var cartIsActive = minecarts.find(function(t){
|
||||
return t.id == existingId;
|
||||
});
|
||||
|
||||
@ -92,9 +93,7 @@ export default L.LayerGroup.extend({
|
||||
this.currentObjects = {};
|
||||
this.clearLayers();
|
||||
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
|
||||
this.minecarts.forEach(function(cart){
|
||||
minecarts.forEach(function(cart){
|
||||
if (!self.isCartInCurrentLayer(cart)){
|
||||
//not in current layer
|
||||
return;
|
||||
@ -108,14 +107,12 @@ export default L.LayerGroup.extend({
|
||||
},
|
||||
|
||||
onAdd: function(/*map*/) {
|
||||
this.layerMgr.addListener(this.reDraw);
|
||||
this.wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
this.reDraw();
|
||||
},
|
||||
|
||||
onRemove: function(/*map*/) {
|
||||
this.clearLayers();
|
||||
this.layerMgr.removeListener(this.reDraw);
|
||||
this.wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
}
|
||||
});
|
@ -9,8 +9,8 @@ var MissionIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "mission", MissionIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "mission", MissionIcon);
|
||||
},
|
||||
|
||||
createPopup: function(mission){
|
@ -1,3 +1,12 @@
|
||||
import wsChannel from '../../WebSocketChannel.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
let players = [];
|
||||
|
||||
//update players all the time
|
||||
wsChannel.addListener("minetest-info", function(info){
|
||||
players = info.players || [];
|
||||
});
|
||||
|
||||
var PlayerIcon = L.icon({
|
||||
iconUrl: 'pics/sam.png',
|
||||
@ -8,22 +17,13 @@ var PlayerIcon = L.icon({
|
||||
});
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
initialize: function() {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.layerMgr = layerMgr;
|
||||
this.wsChannel = wsChannel;
|
||||
|
||||
this.currentObjects = {}; // name => marker
|
||||
this.players = [];
|
||||
|
||||
this.reDraw = this.reDraw.bind(this);
|
||||
this.onMinetestUpdate = this.onMinetestUpdate.bind(this);
|
||||
|
||||
//update players all the time
|
||||
this.wsChannel.addListener("minetest-info", function(info){
|
||||
this.players = info.players || [];
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
createPopup: function(player){
|
||||
@ -62,14 +62,17 @@ export default L.LayerGroup.extend({
|
||||
},
|
||||
|
||||
isPlayerInCurrentLayer: function(player){
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
return (player.pos.y >= (mapLayer.from*16) && player.pos.y <= (mapLayer.to*16));
|
||||
return (
|
||||
player.pos.y >= (mapLayer.from*16) &&
|
||||
player.pos.y <= ((mapLayer.to*16) + 15)
|
||||
);
|
||||
},
|
||||
|
||||
onMinetestUpdate: function(/*info*/){
|
||||
|
||||
this.players.forEach(player => {
|
||||
players.forEach(player => {
|
||||
var isInLayer = this.isPlayerInCurrentLayer(player);
|
||||
|
||||
if (!isInLayer){
|
||||
@ -99,7 +102,7 @@ export default L.LayerGroup.extend({
|
||||
});
|
||||
|
||||
Object.keys(this.currentObjects).forEach(existingName => {
|
||||
var playerIsActive = this.players.find(function(p){
|
||||
var playerIsActive = players.find(function(p){
|
||||
return p.name == existingName;
|
||||
});
|
||||
|
||||
@ -115,9 +118,7 @@ export default L.LayerGroup.extend({
|
||||
this.currentObjects = {};
|
||||
this.clearLayers();
|
||||
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
|
||||
this.players.forEach(player => {
|
||||
players.forEach(player => {
|
||||
if (!this.isPlayerInCurrentLayer(player)){
|
||||
//not in current layer
|
||||
return;
|
||||
@ -131,14 +132,12 @@ export default L.LayerGroup.extend({
|
||||
},
|
||||
|
||||
onAdd: function(/*map*/) {
|
||||
this.layerMgr.addListener(this.reDraw);
|
||||
this.wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
this.reDraw();
|
||||
},
|
||||
|
||||
onRemove: function(/*map*/) {
|
||||
this.clearLayers();
|
||||
this.layerMgr.removeListener(this.reDraw);
|
||||
this.wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
}
|
||||
});
|
@ -1,8 +1,8 @@
|
||||
import AbstractIconOverlay from './AbstractIconOverlay.js';
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "poi");
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "poi");
|
||||
},
|
||||
|
||||
getIcon: function(obj){
|
@ -1,8 +1,8 @@
|
||||
import AbstractGeoJsonOverlay from './AbstractGeoJsonOverlay.js';
|
||||
|
||||
export default AbstractGeoJsonOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "privprotector");
|
||||
initialize: function() {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, "privprotector");
|
||||
},
|
||||
|
||||
createFeature: function(protector){
|
@ -1,8 +1,8 @@
|
||||
import AbstractGeoJsonOverlay from './AbstractGeoJsonOverlay.js';
|
||||
|
||||
export default AbstractGeoJsonOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "protector");
|
||||
initialize: function() {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, "protector");
|
||||
},
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
@ -16,8 +16,8 @@ var ShopEmptyIcon = L.icon({
|
||||
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "shop");
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "shop");
|
||||
},
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
@ -9,8 +9,8 @@ var TechnicAnchorIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "technicanchor", TechnicAnchorIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "technicanchor", TechnicAnchorIcon);
|
||||
},
|
||||
|
||||
createPopup: function(lcd){
|
@ -9,8 +9,8 @@ var TechnicQuarryIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "technicquarry", TechnicQuarryIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "technicquarry", TechnicQuarryIcon);
|
||||
},
|
||||
|
||||
createPopup: function(quarry){
|
@ -9,8 +9,8 @@ var TechnicSwitchIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "technicswitch", TechnicSwitchIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "technicswitch", TechnicSwitchIcon);
|
||||
},
|
||||
|
||||
createPopup: function(sw){
|
@ -1,3 +1,5 @@
|
||||
import wsChannel from '../../WebSocketChannel.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
function getTrainImageUrlForType(type){
|
||||
switch(type){
|
||||
@ -29,23 +31,20 @@ function getTrainImageUrlForType(type){
|
||||
}
|
||||
}
|
||||
|
||||
let trains = [];
|
||||
|
||||
//update trains all the time
|
||||
wsChannel.addListener("minetest-info", function(info){
|
||||
trains = info.trains || [];
|
||||
});
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
initialize: function() {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.layerMgr = layerMgr;
|
||||
this.wsChannel = wsChannel;
|
||||
|
||||
this.currentObjects = {}; // name => marker
|
||||
this.trains = [];
|
||||
|
||||
this.reDraw = this.reDraw.bind(this);
|
||||
this.onMinetestUpdate = this.onMinetestUpdate.bind(this);
|
||||
|
||||
//update players all the time
|
||||
this.wsChannel.addListener("minetest-info", function(info){
|
||||
this.trains = info.trains || [];
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
createPopup: function(train){
|
||||
@ -68,7 +67,7 @@ export default L.LayerGroup.extend({
|
||||
|
||||
|
||||
getMaxDisplayedZoom: function(){
|
||||
return 8;
|
||||
return 10;
|
||||
},
|
||||
|
||||
createMarker: function(train){
|
||||
@ -100,7 +99,7 @@ export default L.LayerGroup.extend({
|
||||
},
|
||||
|
||||
isTrainInCurrentLayer: function(train){
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
return (train.pos.y >= (mapLayer.from*16) && train.pos.y <= (mapLayer.to*16));
|
||||
},
|
||||
@ -114,7 +113,7 @@ export default L.LayerGroup.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
this.trains.forEach(train => {
|
||||
trains.forEach(train => {
|
||||
var isInLayer = this.isTrainInCurrentLayer(train);
|
||||
|
||||
if (!isInLayer){
|
||||
@ -144,7 +143,7 @@ export default L.LayerGroup.extend({
|
||||
});
|
||||
|
||||
Object.keys(this.currentObjects).forEach(existingId => {
|
||||
var trainIsActive = this.trains.find(function(t){
|
||||
var trainIsActive = trains.find(function(t){
|
||||
return t.id == existingId;
|
||||
});
|
||||
|
||||
@ -164,9 +163,9 @@ export default L.LayerGroup.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
this.trains.forEach(train => {
|
||||
trains.forEach(train => {
|
||||
if (!this.isTrainInCurrentLayer(train)){
|
||||
//not in current layer
|
||||
return;
|
||||
@ -181,14 +180,12 @@ export default L.LayerGroup.extend({
|
||||
|
||||
onAdd: function(map) {
|
||||
this.map = map;
|
||||
this.layerMgr.addListener(() => this.reDraw());
|
||||
this.wsChannel.addListener("minetest-info", () => this.onMinetestUpdate());
|
||||
wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
this.reDraw();
|
||||
},
|
||||
|
||||
onRemove: function(/*map*/) {
|
||||
this.clearLayers();
|
||||
this.layerMgr.removeListener(() => this.reDraw());
|
||||
this.wsChannel.removeListener("minetest-info", () => this.onMinetestUpdate());
|
||||
wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
}
|
||||
});
|
@ -1,8 +1,8 @@
|
||||
import AbstractGeoJsonOverlay from './AbstractGeoJsonOverlay.js';
|
||||
|
||||
export default AbstractGeoJsonOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "train");
|
||||
initialize: function() {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, "train");
|
||||
},
|
||||
|
||||
createGeoJson: function(objects){
|
@ -1,3 +1,5 @@
|
||||
import wsChannel from '../../WebSocketChannel.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
var IconOn = L.icon({
|
||||
iconUrl: "pics/advtrains/advtrains_signal_on.png",
|
||||
@ -13,25 +15,19 @@ var IconOff = L.icon({
|
||||
popupAnchor: [0, -16]
|
||||
});
|
||||
|
||||
let signals = [];
|
||||
|
||||
//update signals all the time
|
||||
wsChannel.addListener("minetest-info", function(info){
|
||||
signals = info.signals || [];
|
||||
});
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
initialize: function() {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.layerMgr = layerMgr;
|
||||
this.wsChannel = wsChannel;
|
||||
|
||||
this.currentObjects = {}; // name => marker
|
||||
this.signals = [];
|
||||
|
||||
this.reDraw = this.reDraw.bind(this);
|
||||
this.onMinetestUpdate = this.onMinetestUpdate.bind(this);
|
||||
|
||||
//update players all the time
|
||||
this.wsChannel.addListener("minetest-info", function(info){
|
||||
this.signals = info.signals || [];
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
createPopup: function(signal){
|
||||
@ -61,7 +57,7 @@ export default L.LayerGroup.extend({
|
||||
},
|
||||
|
||||
isSignalInCurrentLayer: function(signal){
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
return (signal.pos.y >= (mapLayer.from*16) && signal.pos.y <= (mapLayer.to*16));
|
||||
},
|
||||
@ -75,7 +71,7 @@ export default L.LayerGroup.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
this.signals.forEach(signal => {
|
||||
signals.forEach(signal => {
|
||||
var isInLayer = this.isSignalInCurrentLayer(signal);
|
||||
var signalId = this.hashPos(signal.pos.x, signal.pos.y, signal.pos.z);
|
||||
|
||||
@ -107,7 +103,7 @@ export default L.LayerGroup.extend({
|
||||
});
|
||||
|
||||
Object.keys(this.currentObjects).forEach(existingId => {
|
||||
var signalIsActive = this.signals.find((t) => {
|
||||
var signalIsActive = signals.find((t) => {
|
||||
var hash = this.hashPos(t.pos.x, t.pos.y, t.pos.z);
|
||||
return hash == existingId;
|
||||
});
|
||||
@ -127,9 +123,9 @@ export default L.LayerGroup.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||
var mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
this.signals.forEach(signal => {
|
||||
signals.forEach(signal => {
|
||||
if (!this.isSignalInCurrentLayer(signal)){
|
||||
//not in current layer
|
||||
return;
|
||||
@ -145,14 +141,12 @@ export default L.LayerGroup.extend({
|
||||
|
||||
onAdd: function(map) {
|
||||
this.map = map;
|
||||
this.layerMgr.addListener(() => this.reDraw());
|
||||
this.wsChannel.addListener("minetest-info", () => this.onMinetestUpdate());
|
||||
wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
this.reDraw();
|
||||
},
|
||||
|
||||
onRemove: function(/*map*/) {
|
||||
this.clearLayers();
|
||||
this.layerMgr.removeListener(() => this.reDraw());
|
||||
this.wsChannel.removeListener("minetest-info", () => this.onMinetestUpdate());
|
||||
wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
}
|
||||
});
|
@ -9,8 +9,8 @@ var TravelnetIcon = L.icon({
|
||||
});
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "travelnet", TravelnetIcon);
|
||||
initialize: function() {
|
||||
AbstractIconOverlay.prototype.initialize.call(this, "travelnet", TravelnetIcon);
|
||||
},
|
||||
|
||||
createPopup: function(travelnet){
|
@ -1,8 +1,8 @@
|
||||
import AbstractGeoJsonOverlay from './AbstractGeoJsonOverlay.js';
|
||||
|
||||
export default AbstractGeoJsonOverlay.extend({
|
||||
initialize: function(wsChannel, layerMgr) {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, wsChannel, layerMgr, "xpprotector");
|
||||
initialize: function() {
|
||||
AbstractGeoJsonOverlay.prototype.initialize.call(this, "xpprotector");
|
||||
},
|
||||
|
||||
createFeature: function(protector){
|
@ -1,5 +1,5 @@
|
||||
|
||||
m.mount(document.getElementById("image-map"), {
|
||||
m.mount(document.getElementById("app"), {
|
||||
view: function(){
|
||||
return m("div", "I'm sorry, your browser is just too old ;)");
|
||||
}
|
||||
|
10
static/js/rollup.config.js
Normal file
10
static/js/rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
export default {
|
||||
input: 'main.js',
|
||||
output: {
|
||||
file :'bundle.js',
|
||||
format: 'umd',
|
||||
sourcemap: true,
|
||||
compact: true
|
||||
}
|
||||
};
|
8
static/js/routes.js
Normal file
8
static/js/routes.js
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
import Map from './components/Map.js';
|
||||
import Search from './components/Search.js';
|
||||
|
||||
export default {
|
||||
"/map/:layerId/:zoom/:lon/:lat": Map,
|
||||
"/search/:query": Search
|
||||
};
|
@ -1,36 +0,0 @@
|
||||
|
||||
import SearchService from './SearchService.js';
|
||||
import SearchStore from './SearchStore.js';
|
||||
import SearchResult from './SearchResult.js';
|
||||
|
||||
export default {
|
||||
view: function(vnode){
|
||||
|
||||
var style = {};
|
||||
|
||||
if (!SearchStore.show) {
|
||||
style.display = "none";
|
||||
}
|
||||
|
||||
function close(){
|
||||
SearchService.clear();
|
||||
}
|
||||
|
||||
function getContent(){
|
||||
if (SearchStore.busy){
|
||||
return m("div", m("i", { class: "fa fa-spinner"}));
|
||||
} else {
|
||||
return m(SearchResult, { map: vnode.attrs.map });
|
||||
}
|
||||
}
|
||||
|
||||
return m("div", { class: "card", id: "search-menu", style: style }, [
|
||||
m("div", { class: "card-header" }, [
|
||||
m("i", { class: "fa fa-search"}),
|
||||
"Search",
|
||||
m("i", { class: "fa fa-times float-right", onclick: close }),
|
||||
]),
|
||||
m("div", { class: "card-body", style: {overflow: "auto"} }, getContent())
|
||||
]);
|
||||
}
|
||||
};
|
@ -1,62 +0,0 @@
|
||||
import SearchStore from './SearchStore.js';
|
||||
import { getMapObjects } from '../api.js';
|
||||
|
||||
export default {
|
||||
|
||||
search: function(){
|
||||
SearchStore.show = true;
|
||||
this.fetchData();
|
||||
},
|
||||
|
||||
fetchData: function(){
|
||||
SearchStore.result = [];
|
||||
|
||||
if (!SearchStore.query){
|
||||
return;
|
||||
}
|
||||
|
||||
SearchStore.busy = true;
|
||||
|
||||
function searchFor(type, key, valuelike){
|
||||
return getMapObjects({
|
||||
pos1: { x:-2048, y:-2048, z:-2048 },
|
||||
pos2: { x:2048, y:2048, z:2048 },
|
||||
type: type,
|
||||
attributelike: {
|
||||
key: key,
|
||||
value: "%" + valuelike +"%"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var prom_list = [
|
||||
searchFor("shop", "out_item", SearchStore.query),
|
||||
searchFor("poi", "name", SearchStore.query),
|
||||
searchFor("train", "station", SearchStore.query),
|
||||
searchFor("travelnet", "station_name", SearchStore.query),
|
||||
searchFor("bones", "owner", SearchStore.query),
|
||||
searchFor("locator", "name", SearchStore.query),
|
||||
searchFor("label", "text", SearchStore.query),
|
||||
searchFor("digiterm", "display_text", SearchStore.query),
|
||||
searchFor("digilinelcd", "text", SearchStore.query)
|
||||
];
|
||||
|
||||
Promise.all(prom_list)
|
||||
.then(function(results){
|
||||
|
||||
var arr = [];
|
||||
results.forEach(function(r) {
|
||||
arr = arr.concat(r);
|
||||
});
|
||||
|
||||
SearchStore.result = arr;
|
||||
SearchStore.busy = false;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
clear: function(){
|
||||
SearchStore.result = [];
|
||||
SearchStore.show = false;
|
||||
}
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
|
||||
export default {
|
||||
query: "",
|
||||
show: false,
|
||||
busy: false,
|
||||
result: []
|
||||
};
|
@ -3,6 +3,8 @@ package tilerenderer
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
"image"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
@ -14,11 +16,6 @@ import (
|
||||
"mapserver/tiledb"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
type TileRenderer struct {
|
||||
@ -29,6 +26,33 @@ type TileRenderer struct {
|
||||
Eventbus *eventbus.Eventbus
|
||||
}
|
||||
|
||||
func resizeImage(src *image.NRGBA, tgt *image.NRGBA, xoffset int, yoffset int) {
|
||||
if src == nil {
|
||||
return
|
||||
}
|
||||
w := src.Bounds().Dy() >> 1
|
||||
h := src.Bounds().Dx() >> 1
|
||||
sinc := src.Bounds().Dy() * 4
|
||||
tinc := tgt.Bounds().Dx() * 4
|
||||
|
||||
for y := 0; y < h; y++ {
|
||||
six := y * sinc * 2
|
||||
tix := 4*xoffset + (yoffset+y)*tinc
|
||||
for x := 0; x < w; x++ {
|
||||
r := (uint16(src.Pix[six]) + uint16(src.Pix[six+4]) + uint16(src.Pix[six+sinc]) + uint16(src.Pix[six+sinc+4])) >> 2
|
||||
g := (uint16(src.Pix[six+1]) + uint16(src.Pix[six+5]) + uint16(src.Pix[six+sinc+1]) + uint16(src.Pix[six+sinc+5])) >> 2
|
||||
b := (uint16(src.Pix[six+2]) + uint16(src.Pix[six+6]) + uint16(src.Pix[six+sinc+2]) + uint16(src.Pix[six+sinc+6])) >> 2
|
||||
a := (uint16(src.Pix[six+3]) + uint16(src.Pix[six+7]) + uint16(src.Pix[six+sinc+3]) + uint16(src.Pix[six+sinc+7])) >> 2
|
||||
tgt.Pix[tix] = uint8(r)
|
||||
tgt.Pix[tix+1] = uint8(g)
|
||||
tgt.Pix[tix+2] = uint8(b)
|
||||
tgt.Pix[tix+3] = uint8(a)
|
||||
tix += 4
|
||||
six += 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewTileRenderer(mapblockrenderer *mapblockrenderer.MapBlockRenderer,
|
||||
tdb *tiledb.TileDB,
|
||||
dba db.DBAccessor,
|
||||
@ -44,38 +68,34 @@ func NewTileRenderer(mapblockrenderer *mapblockrenderer.MapBlockRenderer,
|
||||
}
|
||||
|
||||
const (
|
||||
IMG_SIZE = 256
|
||||
IMG_SIZE = 256
|
||||
SUB_IMG_SIZE = IMG_SIZE >> 1
|
||||
)
|
||||
|
||||
func (tr *TileRenderer) Render(tc *coords.TileCoords) ([]byte, error) {
|
||||
func (tr *TileRenderer) Render(tc *coords.TileCoords) error {
|
||||
//No tile in db
|
||||
img, data, err := tr.renderImage(tc, 2)
|
||||
_, err := tr.renderImage(tc, 2)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if img == nil {
|
||||
//empty tile
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return data, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (*image.NRGBA, []byte, error) {
|
||||
func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (*image.NRGBA, error) {
|
||||
|
||||
if recursionDepth < 2 {
|
||||
cachedtile, err := tr.tdb.GetTile(tc)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cachedtile != nil {
|
||||
reader := bytes.NewReader(cachedtile)
|
||||
cachedimg, err := png.Decode(reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rect := image.Rectangle{
|
||||
@ -87,14 +107,14 @@ func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (
|
||||
draw.Draw(img, rect, cachedimg, image.ZP, draw.Src)
|
||||
|
||||
log.WithFields(logrus.Fields{"x": tc.X, "y": tc.Y, "zoom": tc.Zoom}).Debug("Cached image")
|
||||
return img, cachedtile, nil
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
|
||||
if recursionDepth <= 1 && tc.Zoom < 13 {
|
||||
//non-cached layer and not in "origin" zoom, skip tile
|
||||
log.WithFields(logrus.Fields{"x": tc.X, "y": tc.Y, "zoom": tc.Zoom}).Debug("Skip image")
|
||||
return nil, nil, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{"x": tc.X, "y": tc.Y, "zoom": tc.Zoom}).Debug("RenderImage")
|
||||
@ -106,11 +126,11 @@ func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (
|
||||
currentLayer := layer.FindLayerById(tr.layers, tc.LayerId)
|
||||
|
||||
if currentLayer == nil {
|
||||
return nil, nil, errors.New("No layer found")
|
||||
return nil, errors.New("No layer found")
|
||||
}
|
||||
|
||||
if tc.Zoom > 13 || tc.Zoom < 1 {
|
||||
return nil, nil, errors.New("Invalid zoom")
|
||||
return nil, errors.New("Invalid zoom")
|
||||
}
|
||||
|
||||
if tc.Zoom == 13 {
|
||||
@ -129,17 +149,17 @@ func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (
|
||||
}
|
||||
log.WithFields(fields).Debug("mapblock render from tilerender")
|
||||
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if img == nil {
|
||||
return nil, nil, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
png.Encode(buf, img)
|
||||
|
||||
return img, buf.Bytes(), nil
|
||||
return img, nil
|
||||
}
|
||||
|
||||
//zoom 1-12
|
||||
@ -155,24 +175,24 @@ func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (
|
||||
|
||||
start := time.Now()
|
||||
|
||||
upperLeft, _, err := tr.renderImage(quads.UpperLeft, recursionDepth-1)
|
||||
upperLeft, err := tr.renderImage(quads.UpperLeft, recursionDepth-1)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
upperRight, _, err := tr.renderImage(quads.UpperRight, recursionDepth-1)
|
||||
upperRight, err := tr.renderImage(quads.UpperRight, recursionDepth-1)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lowerLeft, _, err := tr.renderImage(quads.LowerLeft, recursionDepth-1)
|
||||
lowerLeft, err := tr.renderImage(quads.LowerLeft, recursionDepth-1)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lowerRight, _, err := tr.renderImage(quads.LowerRight, recursionDepth-1)
|
||||
lowerRight, err := tr.renderImage(quads.LowerRight, recursionDepth-1)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
@ -186,29 +206,10 @@ func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (
|
||||
},
|
||||
)
|
||||
|
||||
rect := image.Rect(0, 0, 128, 128)
|
||||
if upperLeft != nil {
|
||||
resizedImg := imaging.Resize(upperLeft, 128, 128, imaging.Lanczos)
|
||||
draw.Draw(img, rect, resizedImg, image.ZP, draw.Src)
|
||||
}
|
||||
|
||||
rect = image.Rect(128, 0, 256, 128)
|
||||
if upperRight != nil {
|
||||
resizedImg := imaging.Resize(upperRight, 128, 128, imaging.Lanczos)
|
||||
draw.Draw(img, rect, resizedImg, image.ZP, draw.Src)
|
||||
}
|
||||
|
||||
rect = image.Rect(0, 128, 128, 256)
|
||||
if lowerLeft != nil {
|
||||
resizedImg := imaging.Resize(lowerLeft, 128, 128, imaging.Lanczos)
|
||||
draw.Draw(img, rect, resizedImg, image.ZP, draw.Src)
|
||||
}
|
||||
|
||||
rect = image.Rect(128, 128, 256, 256)
|
||||
if lowerRight != nil {
|
||||
resizedImg := imaging.Resize(lowerRight, 128, 128, imaging.Lanczos)
|
||||
draw.Draw(img, rect, resizedImg, image.ZP, draw.Src)
|
||||
}
|
||||
resizeImage(upperLeft, img, 0, 0)
|
||||
resizeImage(upperRight, img, SUB_IMG_SIZE, 0)
|
||||
resizeImage(lowerLeft, img, 0, SUB_IMG_SIZE)
|
||||
resizeImage(lowerRight, img, SUB_IMG_SIZE, SUB_IMG_SIZE)
|
||||
|
||||
t = time.Now()
|
||||
quadresize := t.Sub(start)
|
||||
@ -242,5 +243,5 @@ func (tr *TileRenderer) renderImage(tc *coords.TileCoords, recursionDepth int) (
|
||||
|
||||
tr.Eventbus.Emit(eventbus.TILE_RENDERED, tc)
|
||||
|
||||
return img, buf.Bytes(), nil
|
||||
return img, nil
|
||||
}
|
||||
|
@ -72,14 +72,11 @@ func BenchmarkTileRender(b *testing.B) {
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
|
||||
data, err := tr.Render(coord)
|
||||
err := tr.Render(coord)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
panic("no data")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package tilerenderer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"mapserver/colormapping"
|
||||
"mapserver/coords"
|
||||
@ -69,30 +68,16 @@ func TestTileRender(t *testing.T) {
|
||||
}
|
||||
|
||||
coord := coords.NewTileCoords(0, 0, 12, 0)
|
||||
data, err := tr.Render(coord)
|
||||
err = tr.Render(coord)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
panic("no data")
|
||||
}
|
||||
|
||||
f, _ := os.Create("../test-output/0_0_12.png")
|
||||
bytes.NewReader(data).WriteTo(f)
|
||||
|
||||
coord1 := coord.GetZoomedOutTile()
|
||||
|
||||
data, err = tr.Render(coord1)
|
||||
err = tr.Render(coord1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
panic("no data")
|
||||
}
|
||||
|
||||
f, _ = os.Create("../test-output/0_0_13.png")
|
||||
bytes.NewReader(data).WriteTo(f)
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ func worker(ctx *app.App, coords <-chan *coords.TileCoords, done chan bool) {
|
||||
}
|
||||
logrus.WithFields(fields).Debug("Tile render job tile")
|
||||
|
||||
_, err := ctx.Tilerenderer.Render(tc)
|
||||
err := ctx.Tilerenderer.Render(tc)
|
||||
if err != nil {
|
||||
fields := logrus.Fields{
|
||||
"X": tc.X,
|
||||
|
Loading…
Reference in New Issue
Block a user