diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..5e01fdd --- /dev/null +++ b/.github/workflows/docker.yml @@ -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 + diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml new file mode 100644 index 0000000..12b0d6f --- /dev/null +++ b/.github/workflows/go-test.yml @@ -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 ./... + diff --git a/.github/workflows/jshint.yml b/.github/workflows/jshint.yml new file mode 100644 index 0000000..916b97c --- /dev/null +++ b/.github/workflows/jshint.yml @@ -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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0aa7d6b --- /dev/null +++ b/.github/workflows/release.yml @@ -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-*' diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 04c67b3..0000000 --- a/.travis.yml +++ /dev/null @@ -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 diff --git a/Dockerfile b/Dockerfile index 2f156aa..aa0933a 100644 --- a/Dockerfile +++ b/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"] diff --git a/Makefile b/Makefile index d7f2c00..e3ee5cc 100644 --- a/Makefile +++ b/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 diff --git a/app/setup.go b/app/setup.go index 4398887..50d23b6 100644 --- a/app/setup.go +++ b/app/setup.go @@ -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 { diff --git a/doc/changelog.md b/doc/changelog.md index df57321..38e8faf 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -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 diff --git a/doc/get_trainlines.sh b/doc/get_trainlines.sh new file mode 100644 index 0000000..545fdc0 --- /dev/null +++ b/doc/get_trainlines.sh @@ -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 + diff --git a/doc/install.md b/doc/install.md index a7eeda8..dd82528 100644 --- a/doc/install.md +++ b/doc/install.md @@ -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. diff --git a/doc/recommended_specs.md b/doc/recommended_specs.md new file mode 100644 index 0000000..75456aa --- /dev/null +++ b/doc/recommended_specs.md @@ -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: + + + +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: + + + +# Recap + +If your setup looks something like this, don't worry about performance: + +* 4+ cores +* 8+ GB RAM +* 20+ GB SSD +* Postgres DB + diff --git a/docker_builder/Dockerfile b/docker_builder/Dockerfile index c8ae46c..ae6a6a3 100644 --- a/docker_builder/Dockerfile +++ b/docker_builder/Dockerfile @@ -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 diff --git a/go.mod b/go.mod index d3205d1..ec29523 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 8841f62..b5e4d5d 100644 --- a/go.sum +++ b/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= diff --git a/mapblockparser/mapblock.go b/mapblockparser/mapblock.go index 33f6bf9..36438c0 100644 --- a/mapblockparser/mapblock.go +++ b/mapblockparser/mapblock.go @@ -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 } diff --git a/mapblockparser/metadata.go b/mapblockparser/metadata.go index 62abcc0..2387d12 100644 --- a/mapblockparser/metadata.go +++ b/mapblockparser/metadata.go @@ -155,6 +155,7 @@ func parseMetadata(mapblock *MapBlock, data []byte) (int, error) { } currentInventory.Items = append(currentInventory.Items, &item) + currentInventory.Size += 1 } diff --git a/mapblockrenderer/renderer.go b/mapblockrenderer/renderer.go index 5362a6e..a859783 100644 --- a/mapblockrenderer/renderer.go +++ b/mapblockrenderer/renderer.go @@ -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 } diff --git a/mapobject/bones.go b/mapobject/bones.go index f87bf06..232d452 100644 --- a/mapobject/bones.go +++ b/mapobject/bones.go @@ -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 } diff --git a/mapobject/fancyvend.go b/mapobject/fancyvend.go index e211559..3719f42 100644 --- a/mapobject/fancyvend.go +++ b/mapobject/fancyvend.go @@ -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 diff --git a/mapobject/smartshop.go b/mapobject/smartshop.go index 072a35a..df4dfd7 100644 --- a/mapobject/smartshop.go +++ b/mapobject/smartshop.go @@ -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 diff --git a/pics/cpu_graph.png b/pics/cpu_graph.png new file mode 100644 index 0000000..1f8491d Binary files /dev/null and b/pics/cpu_graph.png differ diff --git a/pics/network_graph.png b/pics/network_graph.png new file mode 100644 index 0000000..2b3dc46 Binary files /dev/null and b/pics/network_graph.png differ diff --git a/readme.md b/readme.md index bfc3145..35c0625 100644 --- a/readme.md +++ b/readme.md @@ -1,13 +1,15 @@ Minetest mapserver ======= - -[![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) + + 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 diff --git a/static/colors/custom.txt b/static/colors/custom.txt index f3a4e18..8593096 100644 --- a/static/colors/custom.txt +++ b/static/colors/custom.txt @@ -4,4 +4,13 @@ planetoidgen:sun 255 100 0 # beacon beacon:redbeam 255 0 0 -beacon:greenbeam 0 255 0 \ No newline at end of file +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 diff --git a/static/css/custom.css b/static/css/custom.css index 343f9a5..3f5f1b3 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -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; diff --git a/static/index.html b/static/index.html index 5b98d85..1c467ce 100644 --- a/static/index.html +++ b/static/index.html @@ -15,8 +15,10 @@ Minetest Mapserver -
-
+
+
+
Starting mapserver...
+
@@ -25,9 +27,9 @@ - + - - + + diff --git a/static/js/.gitignore b/static/js/.gitignore new file mode 100644 index 0000000..98e2724 --- /dev/null +++ b/static/js/.gitignore @@ -0,0 +1,2 @@ +bundle.js +bundle.js.map diff --git a/static/js/.jshintignore b/static/js/.jshintignore new file mode 100644 index 0000000..d4ea404 --- /dev/null +++ b/static/js/.jshintignore @@ -0,0 +1,2 @@ +bundle.js +lib/* diff --git a/static/js/Hashroute.js b/static/js/Hashroute.js deleted file mode 100644 index f3b3777..0000000 --- a/static/js/Hashroute.js +++ /dev/null @@ -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]; - } - -}; diff --git a/static/js/LayerManager.js b/static/js/LayerManager.js index 6d0d395..2053bce 100644 --- a/static/js/LayerManager.js +++ b/static/js/LayerManager.js @@ -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; } diff --git a/static/js/SearchControl.js b/static/js/SearchControl.js deleted file mode 100644 index 1aa228f..0000000 --- a/static/js/SearchControl.js +++ /dev/null @@ -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; - } -}); diff --git a/static/js/compat.js b/static/js/compat.js new file mode 100644 index 0000000..9aba1fe --- /dev/null +++ b/static/js/compat.js @@ -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]}`; + } + } +} diff --git a/static/js/components/LayerSelector.js b/static/js/components/LayerSelector.js new file mode 100644 index 0000000..98a1de6 --- /dev/null +++ b/static/js/components/LayerSelector.js @@ -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); + } +}; diff --git a/static/js/components/Map.js b/static/js/components/Map.js new file mode 100644 index 0000000..54c3f74 --- /dev/null +++ b/static/js/components/Map.js @@ -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(); + } +}; diff --git a/static/js/components/Search.js b/static/js/components/Search.js new file mode 100644 index 0000000..668db86 --- /dev/null +++ b/static/js/components/Search.js @@ -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 }); + } + } +}; diff --git a/static/js/search/SearchInput.js b/static/js/components/SearchInput.js similarity index 59% rename from static/js/search/SearchInput.js rename to static/js/components/SearchInput.js index b584f03..be43df3 100644 --- a/static/js/search/SearchInput.js +++ b/static/js/components/SearchInput.js @@ -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"}) ]) diff --git a/static/js/search/SearchResult.js b/static/js/components/SearchResult.js similarity index 88% rename from static/js/search/SearchResult.js rename to static/js/components/SearchResult.js index 811b812..1ac8c51 100644 --- a/static/js/search/SearchResult.js +++ b/static/js/components/SearchResult.js @@ -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}, [ diff --git a/static/js/config.js b/static/js/config.js new file mode 100644 index 0000000..b348712 --- /dev/null +++ b/static/js/config.js @@ -0,0 +1,12 @@ + +var config; + +export default { + get(){ + return config; + }, + + set(cfg){ + config = cfg; + } +}; diff --git a/static/js/main.js b/static/js/main.js index 080e9ee..a24ce8f 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -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; +}); diff --git a/static/js/map.js b/static/js/map.js deleted file mode 100644 index 882c015..0000000 --- a/static/js/map.js +++ /dev/null @@ -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('Minetest Mapserver'); - - 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); -} diff --git a/static/js/CoordinatesDisplay.js b/static/js/map/CoordinatesDisplay.js similarity index 100% rename from static/js/CoordinatesDisplay.js rename to static/js/map/CoordinatesDisplay.js diff --git a/static/js/map/CustomOverlay.js b/static/js/map/CustomOverlay.js new file mode 100644 index 0000000..b59a95f --- /dev/null +++ b/static/js/map/CustomOverlay.js @@ -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); + +} diff --git a/static/js/map/MapFactory.js b/static/js/map/MapFactory.js new file mode 100644 index 0000000..95207e2 --- /dev/null +++ b/static/js/map/MapFactory.js @@ -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('Minetest Mapserver'); + + 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; +} diff --git a/static/js/Overlaysetup.js b/static/js/map/Overlaysetup.js similarity index 73% rename from static/js/Overlaysetup.js rename to static/js/map/Overlaysetup.js index 5f71749..374ae9c 100644 --- a/static/js/Overlaysetup.js +++ b/static/js/map/Overlaysetup.js @@ -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); } diff --git a/static/js/RealtimeTileLayer.js b/static/js/map/RealtimeTileLayer.js similarity index 100% rename from static/js/RealtimeTileLayer.js rename to static/js/map/RealtimeTileLayer.js diff --git a/static/js/SimpleCRS.js b/static/js/map/SimpleCRS.js similarity index 100% rename from static/js/SimpleCRS.js rename to static/js/map/SimpleCRS.js diff --git a/static/js/map/TopRightControl.js b/static/js/map/TopRightControl.js new file mode 100644 index 0000000..2750560 --- /dev/null +++ b/static/js/map/TopRightControl.js @@ -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; + } +}); diff --git a/static/js/WorldInfoDisplay.js b/static/js/map/WorldInfoDisplay.js similarity index 100% rename from static/js/WorldInfoDisplay.js rename to static/js/map/WorldInfoDisplay.js diff --git a/static/js/overlays/ATMOverlay.js b/static/js/map/overlays/ATMOverlay.js similarity index 85% rename from static/js/overlays/ATMOverlay.js rename to static/js/map/overlays/ATMOverlay.js index c850ab8..8c63c73 100644 --- a/static/js/overlays/ATMOverlay.js +++ b/static/js/map/overlays/ATMOverlay.js @@ -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(){ diff --git a/static/js/overlays/AbstractGeoJsonOverlay.js b/static/js/map/overlays/AbstractGeoJsonOverlay.js similarity index 80% rename from static/js/overlays/AbstractGeoJsonOverlay.js rename to static/js/map/overlays/AbstractGeoJsonOverlay.js index 1827d32..0ebd5fe 100644 --- a/static/js/overlays/AbstractGeoJsonOverlay.js +++ b/static/js/map/overlays/AbstractGeoJsonOverlay.js @@ -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); } }); diff --git a/static/js/overlays/AbstractIconOverlay.js b/static/js/map/overlays/AbstractIconOverlay.js similarity index 85% rename from static/js/overlays/AbstractIconOverlay.js rename to static/js/map/overlays/AbstractIconOverlay.js index dc5aa12..2c55c3c 100644 --- a/static/js/overlays/AbstractIconOverlay.js +++ b/static/js/map/overlays/AbstractIconOverlay.js @@ -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); } }); diff --git a/static/js/overlays/BonesOverlay.js b/static/js/map/overlays/BonesOverlay.js similarity index 70% rename from static/js/overlays/BonesOverlay.js rename to static/js/map/overlays/BonesOverlay.js index 046a4e8..d77c941 100644 --- a/static/js/overlays/BonesOverlay.js +++ b/static/js/map/overlays/BonesOverlay.js @@ -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){ diff --git a/static/js/overlays/BorderOverlay.js b/static/js/map/overlays/BorderOverlay.js similarity index 94% rename from static/js/overlays/BorderOverlay.js rename to static/js/map/overlays/BorderOverlay.js index 7dbd831..1f5139e 100644 --- a/static/js/overlays/BorderOverlay.js +++ b/static/js/map/overlays/BorderOverlay.js @@ -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(){ diff --git a/static/js/overlays/DigitermOverlay.js b/static/js/map/overlays/DigitermOverlay.js similarity index 70% rename from static/js/overlays/DigitermOverlay.js rename to static/js/map/overlays/DigitermOverlay.js index 1cf1360..5a6d004 100644 --- a/static/js/overlays/DigitermOverlay.js +++ b/static/js/map/overlays/DigitermOverlay.js @@ -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){ diff --git a/static/js/overlays/LabelOverlay.js b/static/js/map/overlays/LabelOverlay.js similarity index 87% rename from static/js/overlays/LabelOverlay.js rename to static/js/map/overlays/LabelOverlay.js index e3802b5..ce1075e 100644 --- a/static/js/overlays/LabelOverlay.js +++ b/static/js/map/overlays/LabelOverlay.js @@ -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 = ` - + 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); } }); diff --git a/static/js/overlays/MissionOverlay.js b/static/js/map/overlays/MissionOverlay.js similarity index 78% rename from static/js/overlays/MissionOverlay.js rename to static/js/map/overlays/MissionOverlay.js index 371aa1e..c454579 100644 --- a/static/js/overlays/MissionOverlay.js +++ b/static/js/map/overlays/MissionOverlay.js @@ -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){ diff --git a/static/js/overlays/PlayerOverlay.js b/static/js/map/overlays/PlayerOverlay.js similarity index 77% rename from static/js/overlays/PlayerOverlay.js rename to static/js/map/overlays/PlayerOverlay.js index 7732f48..4136734 100644 --- a/static/js/overlays/PlayerOverlay.js +++ b/static/js/map/overlays/PlayerOverlay.js @@ -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); } }); diff --git a/static/js/overlays/PoiOverlay.js b/static/js/map/overlays/PoiOverlay.js similarity index 79% rename from static/js/overlays/PoiOverlay.js rename to static/js/map/overlays/PoiOverlay.js index 6f05a2d..06b902e 100644 --- a/static/js/overlays/PoiOverlay.js +++ b/static/js/map/overlays/PoiOverlay.js @@ -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){ diff --git a/static/js/overlays/PrivProtectorOverlay.js b/static/js/map/overlays/PrivProtectorOverlay.js similarity index 81% rename from static/js/overlays/PrivProtectorOverlay.js rename to static/js/map/overlays/PrivProtectorOverlay.js index a75269e..2fe288b 100644 --- a/static/js/overlays/PrivProtectorOverlay.js +++ b/static/js/map/overlays/PrivProtectorOverlay.js @@ -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){ diff --git a/static/js/overlays/ProtectorOverlay.js b/static/js/map/overlays/ProtectorOverlay.js similarity index 83% rename from static/js/overlays/ProtectorOverlay.js rename to static/js/map/overlays/ProtectorOverlay.js index ccbd96b..e13c399 100644 --- a/static/js/overlays/ProtectorOverlay.js +++ b/static/js/map/overlays/ProtectorOverlay.js @@ -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(){ diff --git a/static/js/overlays/ShopOverlay.js b/static/js/map/overlays/ShopOverlay.js similarity index 88% rename from static/js/overlays/ShopOverlay.js rename to static/js/map/overlays/ShopOverlay.js index f8e3a9f..2e94d8a 100644 --- a/static/js/overlays/ShopOverlay.js +++ b/static/js/map/overlays/ShopOverlay.js @@ -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(){ diff --git a/static/js/overlays/TechnicAnchorOverlay.js b/static/js/map/overlays/TechnicAnchorOverlay.js similarity index 76% rename from static/js/overlays/TechnicAnchorOverlay.js rename to static/js/map/overlays/TechnicAnchorOverlay.js index 5553767..45d940b 100644 --- a/static/js/overlays/TechnicAnchorOverlay.js +++ b/static/js/map/overlays/TechnicAnchorOverlay.js @@ -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){ diff --git a/static/js/overlays/TechnicQuarryOverlay.js b/static/js/map/overlays/TechnicQuarryOverlay.js similarity index 75% rename from static/js/overlays/TechnicQuarryOverlay.js rename to static/js/map/overlays/TechnicQuarryOverlay.js index f989aca..5461a59 100644 --- a/static/js/overlays/TechnicQuarryOverlay.js +++ b/static/js/map/overlays/TechnicQuarryOverlay.js @@ -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){ diff --git a/static/js/overlays/TechnicSwitchOverlay.js b/static/js/map/overlays/TechnicSwitchOverlay.js similarity index 77% rename from static/js/overlays/TechnicSwitchOverlay.js rename to static/js/map/overlays/TechnicSwitchOverlay.js index dd261c4..8fc0b01 100644 --- a/static/js/overlays/TechnicSwitchOverlay.js +++ b/static/js/map/overlays/TechnicSwitchOverlay.js @@ -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){ diff --git a/static/js/overlays/TrainOverlay.js b/static/js/map/overlays/TrainOverlay.js similarity index 84% rename from static/js/overlays/TrainOverlay.js rename to static/js/map/overlays/TrainOverlay.js index 9f9036a..271331d 100644 --- a/static/js/overlays/TrainOverlay.js +++ b/static/js/map/overlays/TrainOverlay.js @@ -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); } }); diff --git a/static/js/overlays/TrainlineOverlay.js b/static/js/map/overlays/TrainlineOverlay.js similarity index 95% rename from static/js/overlays/TrainlineOverlay.js rename to static/js/map/overlays/TrainlineOverlay.js index 420750b..bf8a1cf 100644 --- a/static/js/overlays/TrainlineOverlay.js +++ b/static/js/map/overlays/TrainlineOverlay.js @@ -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){ diff --git a/static/js/overlays/TrainsignalOverlay.js b/static/js/map/overlays/TrainsignalOverlay.js similarity index 79% rename from static/js/overlays/TrainsignalOverlay.js rename to static/js/map/overlays/TrainsignalOverlay.js index 186d9f9..68c30d2 100644 --- a/static/js/overlays/TrainsignalOverlay.js +++ b/static/js/map/overlays/TrainsignalOverlay.js @@ -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); } }); diff --git a/static/js/overlays/TravelnetOverlay.js b/static/js/map/overlays/TravelnetOverlay.js similarity index 81% rename from static/js/overlays/TravelnetOverlay.js rename to static/js/map/overlays/TravelnetOverlay.js index 199199b..b2dcfd4 100644 --- a/static/js/overlays/TravelnetOverlay.js +++ b/static/js/map/overlays/TravelnetOverlay.js @@ -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){ diff --git a/static/js/overlays/XPProtectorOverlay.js b/static/js/map/overlays/XPProtectorOverlay.js similarity index 82% rename from static/js/overlays/XPProtectorOverlay.js rename to static/js/map/overlays/XPProtectorOverlay.js index 8b55d01..562bd15 100644 --- a/static/js/overlays/XPProtectorOverlay.js +++ b/static/js/map/overlays/XPProtectorOverlay.js @@ -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){ diff --git a/static/js/nomodule.js b/static/js/nomodule.js index 4adba96..c46af90 100644 --- a/static/js/nomodule.js +++ b/static/js/nomodule.js @@ -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 ;)"); } diff --git a/static/js/rollup.config.js b/static/js/rollup.config.js new file mode 100644 index 0000000..bc5416a --- /dev/null +++ b/static/js/rollup.config.js @@ -0,0 +1,10 @@ + +export default { + input: 'main.js', + output: { + file :'bundle.js', + format: 'umd', + sourcemap: true, + compact: true + } +}; diff --git a/static/js/routes.js b/static/js/routes.js new file mode 100644 index 0000000..d12e8df --- /dev/null +++ b/static/js/routes.js @@ -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 +}; diff --git a/static/js/search/SearchMenu.js b/static/js/search/SearchMenu.js deleted file mode 100644 index 66dcc21..0000000 --- a/static/js/search/SearchMenu.js +++ /dev/null @@ -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()) - ]); - } -}; diff --git a/static/js/search/SearchService.js b/static/js/search/SearchService.js deleted file mode 100644 index fe521a8..0000000 --- a/static/js/search/SearchService.js +++ /dev/null @@ -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; - } -}; diff --git a/static/js/search/SearchStore.js b/static/js/search/SearchStore.js deleted file mode 100644 index a154484..0000000 --- a/static/js/search/SearchStore.js +++ /dev/null @@ -1,7 +0,0 @@ - -export default { - query: "", - show: false, - busy: false, - result: [] -}; diff --git a/tilerenderer/renderer.go b/tilerenderer/renderer.go index 39b75ac..38ada5f 100644 --- a/tilerenderer/renderer.go +++ b/tilerenderer/renderer.go @@ -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 } diff --git a/tilerenderer/renderer_benchmark_test.go b/tilerenderer/renderer_benchmark_test.go index 6670f95..fbcac80 100644 --- a/tilerenderer/renderer_benchmark_test.go +++ b/tilerenderer/renderer_benchmark_test.go @@ -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") - } } } diff --git a/tilerenderer/renderer_test.go b/tilerenderer/renderer_test.go index 4dc8ee4..b6f43d4 100644 --- a/tilerenderer/renderer_test.go +++ b/tilerenderer/renderer_test.go @@ -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) - } diff --git a/tilerendererjob/worker.go b/tilerendererjob/worker.go index 553d355..ca6a218 100644 --- a/tilerendererjob/worker.go +++ b/tilerendererjob/worker.go @@ -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,