mtsatellite/cmd/mtwebmapper/client/src/store/index.js

189 lines
4.4 KiB
JavaScript

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
socket: null,
autoUpdate: false,
coordinates: [0, 0],
playersLayer: true,
buildingsLayer: true,
poiLayer: true,
travelnetLayer: true,
otherLayer: true,
players: []
},
mutations: {
updateCoordinates(state, value) {
state.coordinates = value;
},
setAutoUpdate(state, value) {
state.autoUpdate = value
},
updatePlayersLayer(state, value) {
state.playersLayer = value;
},
updateBuildingsLayer(state, value) {
state.buildingsLayer = value;
},
updatePoiLayer(state, value) {
state.poiLayer = value;
},
updateTravelnetLayer(state, value) {
state.travelnetLayer = value;
},
updateOtherLayer(state, value) {
state.otherLayer = value;
},
setPlayers(state, value) {
state.players = value;
},
setPlayerState(state, value) {
const p = state.players.find(p => p.name === value.name)
p.online = value.state;
}
},
actions: {
stopAutoUpdate: function({ state }) {
if (this.socket) {
var s = state.socket;
state.socket = null;
s.close();
}
},
manualUpdate: function({commit}) {
var tiles = document.getElementsByTagName("img");
for (var i = 0; i < tiles.length; i++) {
var img = tiles[i];
var cl = img.getAttribute("class");
if (cl.indexOf("leaflet-tile-loaded") >= 0) {
var src = img.src;
var idx = src.lastIndexOf("#");
if (idx >= 0) {
src = src.substring(0, idx);
}
img.src = src + "#" + Math.random();
}
}
fetch("players").then(response => response.json().then((data) => {
commit("setPlayers", data);
}));
},
runAutoUpdate: function({ commit, state, dispatch}) {
var me = this;
// TODO: Make the URL to websocket configurable via .env
state.socket = new WebSocket('ws://' + window.location.host + '/socket');
state.socket.onerror = function() {
commit('setAutoUpdate', false)
dispatch('stopAutoUpdate');
};
state.socket.onclose = function() {
commit('setAutoUpdate', false)
state.socket = null;
}
state.socket.onopen = function() {
// Sending pings every 5 secs to keep connection alive.
var heartbeat = function() {
if (heartbeat && me.socket) {
me.socket.send("PING");
setTimeout(heartbeat, 8000);
} else {
// Prevent sending pings to re-opened sockets.
heartbeat = null;
}
};
setTimeout(heartbeat, 8000);
};
state.socket.onmessage = function(evt) {
var json = evt.data;
if (!(typeof json === "string")) {
return;
}
var msg;
try {
msg = JSON.parse(json);
}
catch (err) {
return;
}
if (msg.players) {
commit('setPlayers', msg.players);
}
var tilesData = msg.tiles;
if (!tilesData) {
return;
}
var invalidate = function(td) {
var pyramid = new Array(9);
var last = new Object();
pyramid[8] = last;
for (var i = 0; i < td.length; i++) {
var xz = td[i];
last[xz.X + "#" + xz.Z] = xz;
}
for (var p = 7; p >= 0; p--) {
var prev = pyramid[p+1];
var curr = new Object();
pyramid[p] = curr;
for (var k in prev) {
if (Object.prototype.hasOwnProperty.call(prev, k)) {
var oxz = prev[k];
var nxz = { X: oxz.X >> 1, Z: oxz.Z >> 1 };
curr[nxz.X + "#" + nxz.Z] = nxz;
}
}
}
return function(x, y, z) {
if (y > 8) {
x >>= y - 8;
z >>= y - 8;
y = 8;
}
var level = pyramid[y];
var k = x + "#" + z;
return Object.prototype.hasOwnProperty.call(level, k);
};
} (tilesData);
var tiles = document.getElementsByTagName('img');
var re = /\/map\/([0-9]+)\/([0-9]+)\/([0-9]+).*/;
for (var i = 0; i < tiles.length; i++) {
var img = tiles[i];
var cl = img.getAttribute('class');
if (cl.indexOf('leaflet-tile-loaded') < 0) {
continue;
}
var src = img.src;
var coord = src.match(re);
if (coord == null) {
continue;
}
var y = parseInt(coord[1]);
var x = parseInt(coord[2]);
var z = parseInt(coord[3]);
if (invalidate(x, y, z)) {
var idx = src.lastIndexOf('#');
if (idx >= 0) {
src = src.substring(0, idx);
}
img.src = src + '#' + Math.random();
}
}
};
}
}
})