Remove remanent remoteMap code

Remove remoteMap specific code left behind after the removal of the
remoteMap plugin in 6415784.  The plugin interface should be versatile
enough to allow all of this code to reside inside the plugin itself.
This commit is contained in:
Hornwitser committed 2019-08-29 11:38:57 +02:00
1 parent 5d28718175
commit b73b202513
10 files changed
+4 -850

No files matched your search

-1
View File
@@ -47,7 +47,6 @@ saves
sharedPlugins/*
!sharedPlugins/inventoryImports/
!sharedPlugins/UPSdisplay/
!sharedPlugins/remoteMap/
!sharedPlugins/remoteCommands/
!sharedPlugins/researchSync/
!sharedPlugins/globalChat/
+3 -90
View File
@@ -712,83 +712,11 @@ app.get("/api/getFactorioLocale", function(req,res){
});
});
/* Websockets for remoteMap */
/* Websockets for plugins */
var io = require("socket.io")({});
const ioMetrics = require("socket.io-prometheus");
ioMetrics(io);
var slaveMappers = {};
class slaveMapper {
constructor(instanceID, socket) {
this.instanceID = instanceID;
this.socket = socket;
this.lastBeat = Date.now();
this.socket.on("heartbeat", () => {
prometheusWsUsageCounter.labels('heartbeat', this.instanceID).inc();
// we aren't ready to die yet apparently
this.lastBeat = Date.now();
});
this.socket.on("sendChunk", function(data){
prometheusWsUsageCounter.labels('sendChunk', this.instanceID).inc();
mapRequesters[data.requesterID].socket.emit("displayChunk", data);
});
// slaveMapper sent us an entity update, process
this.socket.on("sendEntity", entity => {
prometheusWsUsageCounter.labels('sendEntity', this.instanceID).inc();
Object.keys(mapRequesters).forEach(requesterName => {
let requester = mapRequesters[requesterName];
if(requester.instanceID == this.instanceID){
// this mapRequester is listening to this slaveMapper, so we send it updates
requester.socket.emit("displayEntity", entity);
}
});
});
}
}
var mapRequesters = {};
class mapRequester {
constructor(requesterID, socket, instanceID){
this.requesterID = requesterID;
this.socket = socket;
this.instanceID = instanceID;
this.lastBeat = Date.now();
this.socket.on("heartbeat", () => {
prometheusWsUsageCounter.labels('heartbeat', "other").inc();
// we aren't ready to die yet apparently
this.lastBeat = Date.now();
});
this.socket.on("requestChunk", loc => {
prometheusWsUsageCounter.labels('requestChunk', "other").inc();
loc.requesterID = this.requesterID;
let instanceID = loc.instanceID || this.instanceID;
if(slaveMappers[instanceID] && typeof loc.x == "number" && typeof loc.y == "number"){
slaveMappers[instanceID].socket.emit("getChunk", loc);
}
});
this.socket.on("requestEntity", req => {
prometheusWsUsageCounter.labels('requestEntity', "other").inc();
req.requesterID = this.requesterID;
let instanceID = req.instanceID || this.instanceID;
if(slaveMappers[instanceID] && typeof req.x == "number" && typeof req.y == "number"){
slaveMappers[instanceID].socket.emit("getEntity", req);
}
});
this.socket.on("placeEntity", req => {
prometheusWsUsageCounter.labels('placeEntity', "other").inc();
req.requesterID = this.requesterID;
let instanceID = req.instanceID || this.instanceID;
if(slaveMappers[instanceID]){
slaveMappers[instanceID].socket.emit("placeEntity", req);
}
});
}
}
/* Websockets for send and recieve combinators */
var wsSlaves = {};
@@ -852,8 +780,8 @@ class wsSlave {
io.on('connection', function (socket) {
// cleanup dead sockets from disconnected people
let terminatedConnections = 0;
let currentConnections = Object.keys(mapRequesters).length + Object.keys(slaveMappers).length + Object.keys(wsSlaves).length;
[mapRequesters, slaveMappers, wsSlaves].forEach(list => {
let currentConnections = Object.keys(wsSlaves).length;
[wsSlaves].forEach(list => {
Object.keys(list).forEach(connectionID => {
let connection = list[connectionID];
if(connection.lastBeat < (Date.now() - 30000)){
@@ -867,21 +795,6 @@ io.on('connection', function (socket) {
// tell our friend that we are listening
setTimeout(()=>socket.emit('hello', { hello: 'world' }), 5000);
/* initial processing for remoteMap */
socket.on('registerSlaveMapper', function (data) {
prometheusWsUsageCounter.labels('registerSlaveMapper', "other").inc();
slaveMappers[data.instanceID] = new slaveMapper(data.instanceID, socket);
console.log("remoteMap | SOCKET registered map provider for "+data.instanceID);
});
socket.on('registerMapRequester', function(data){
// data {instanceID:""}
prometheusWsUsageCounter.labels('registerMapRequester', "other").inc();
let requesterID = Math.random().toString();
mapRequesters[requesterID] = new mapRequester(requesterID, socket, data.instanceID);
socket.emit("mapRequesterReady", true);
console.log("remoteMap | SOCKET registered map requester for "+data.instanceID);
});
/* Websockets for send and recieve combinators */
socket.on("registerSlave", function(data) {
prometheusWsUsageCounter.labels('registerSlave', "other").inc();
+1 -1
View File
@@ -37,7 +37,7 @@ describe('Master server endpoint testing', function() {
parallel("#GET static website data", function() {
this.timeout(6000);
let paths = ["/", "/nodes", "/settings", "/nodeDetails", "/remoteMap"];
let paths = ["/", "/nodes", "/settings", "/nodeDetails"];
for (let path of paths) {
it(`sends some HTML when accessing ${path}`, () => getValidate(path));
}
-3
View File
@@ -11,7 +11,4 @@ module.exports = function(app) {
app.get("/nodeDetails", function(req, res) {
res.render("nodeDetails");
});
app.get("/remoteMap", function(req, res) {
res.render("remoteMap");
});
};
-12
View File
@@ -131,18 +131,6 @@ function populateSlaveInfo(){
HTML += '<li class="breadcrumb-item">Last seen: <span id="lastSeenDate">'+moment(Number(slave.time)).fromNow()+"</span></li>";
HTML += '<li class="breadcrumb-item">Online players: '+slave.playerCount+"</li></ol></nav>";
// detect if remoteMap mod is installed, if it is we want to show the link for it
let hasRemoteMap = false;
slave.mods.forEach(mod => {
console.log(mod.modName);
if(mod.modName.includes("remoteMap")){
hasRemoteMap = true; // we are still doing the logic on the outside, in case there are multiple instances of remoteMap installed....
}
});
if(hasRemoteMap){
HTML += "<a href='/remoteMap?instanceID="+getParameterByName("instanceID")+"'>Remote map</a>";
}
HTML += "</div>"; // end of displayBody
// list mods and other metadata
-8
View File
@@ -14,13 +14,6 @@
</div>
<div id="display">
<%
function findInArray(key, value, array){
let indexes = [];
for(let i in array){
if(array[i][key] && array[i][key].includes(value)) indexes.push(i);
}
return indexes;
}
let html = ""
for(let id in slaves){
let slave = slaves[id];
@@ -38,7 +31,6 @@
<li class="list-group-item">IP: ${slave.publicIP}:${slave.serverPort}</li>
<li class="list-group-item">Host: ${slave.mac}</li>
</ul>
${findInArray("modName", "remoteMap", slave.mods).length ? "<a href='/remoteMap?instanceID="+id+"'>Remote map</a>" : ""}
`
for(let o in locals.masterPlugins){
let plug = locals.masterPlugins[o];
-28
View File
@@ -1,28 +0,0 @@
<!doctype HTML>
<head>
<%- include("head.html") %>
<script src="external/socket.io.js"></script>
<script type="module" src="remoteMap.js"></script>
</head>
<body>
<%- include("nav.html") %>
<div id="body">
<h2>remoteMap</h2>
<div id="remoteMapContainer" style="float:left">
<canvas class="remoteMap" id="remoteMapBackground" width="512" height="512" style="border:1px solid #000000;position:absolute;"></canvas>
<canvas class="remoteMap" id="remoteMap" width="512" height="512" style="border:1px solid #000000;position:absolute;"></canvas>
<canvas class="remoteMap" id="remoteMapSelection" width="512" height="512" style="border:1px solid #000000;position:absolute;"></canvas>
</div>
<div id="remoteMapItemSelector" style="float:left">
<!-- Generated by script, don't edit -->
</div>
<div id="remoteMapSettings" style="float:left">
<p>Map size: <input type="number" id="mapSize" style="color:black;"> (default 32)</p>
<p>Tile size: <input type="number" id="tileSize" style="color:black;"> (default 8)</p>
<p>FPS: <input type="number" id="fpsCounter" style="color:black;"></p>
<p>Pause when window is deselected (saves CPU) <input type="checkbox" id="pauseOnBlur"></p>
<p>Movement speed: <input type="number" id="movementSpeed" style="color:black;"> (default 0.2)</p>
</div>
</div>
</body>
-608
View File
@@ -1,608 +0,0 @@
/**
Javascript to download and render a map of a factorio world from an instance using websockets and canvas
It is its responsibility to handle:
* Display settings
* Ordering of canvases
* Querying slaves through master for map info
* Drawing of sprites defined in external files to canvas
* Handling input for placing/removing items
* Transmitting item placements/removals through master
That is way too much for one file, so to anyone reading this:
This file is horribly written and documented.
I am sorry. Drawing code is at the bottom, good luck.
If you have questions and wish to contact me, my name
is Danielv123 on Github, Discord and esperNet #factorio
*/
console.log(":)")
/// ES6 imports
// rules for how entities are drawn (sizes, offset etc)
import {entityDrawRules} from "lib/entityDrawRules.js";
import {getParameterByName, drawImageWithRotation, isImageOk} from "lib/utility.js";
import spritesheetJson from "./pictures/spritesheet.js";
import {itemSelector} from "./remoteMap/itemSelection.js";
var global = {};
var itemSelectorGUI = new itemSelector("#remoteMapItemSelector", [
{name:"stone-furnace"},
{name:"accumulator"},
{name:"electric-furnace"},
{name:"inserter"},
{name:"express-transport-belt"},
]);
if(!localStorage.remoteMapConfig || localStorage.remoteMapConfig == "[object Object]"){
localStorage.remoteMapConfig = JSON.stringify({
mapSize: 32,
tileSize: 8,
movementSpeed: 0.2,
});
}
var remoteMapConfig = JSON.parse(localStorage.remoteMapConfig);
// Handle config changes through UI buttons
(function(){
let selectMapSize = document.querySelector("#mapSize");
let selectTileSize = document.querySelector("#tileSize");
if(selectMapSize && selectTileSize){
selectMapSize.value = Number(remoteMapConfig.mapSize) || 32;
selectTileSize.value = Number(remoteMapConfig.tileSize) || 8;
selectMapSize.onchange = function(){
let config = JSON.parse(localStorage.remoteMapConfig);
config.mapSize = Number(selectMapSize.value);
localStorage.remoteMapConfig = JSON.stringify(config);
console.log("Config updated: "+localStorage.remoteMapConfig);
}
selectTileSize.onchange = function(){
let config = JSON.parse(localStorage.remoteMapConfig);
config.tileSize = Number(selectTileSize.value);
localStorage.remoteMapConfig = JSON.stringify(config);
console.log("Config updated: "+localStorage.remoteMapConfig);
}
}
let pauseOnBlur = document.querySelector("#pauseOnBlur");
if(pauseOnBlur){
pauseOnBlur.checked = localStorage.remoteMapPauseOnBlur || true;
pauseOnBlur.onchange = function(){
localStorage.remoteMapPauseOnBlur = pauseOnBlur.checked;
}
}
let movementSpeed = document.querySelector("#movementSpeed");
if(movementSpeed){
movementSpeed.value = Number(remoteMapConfig.movementSpeed) || 0.2;
movementSpeed.onchange = function(){
let config = JSON.parse(localStorage.remoteMapConfig);
config.movementSpeed = Number(movementSpeed.value);
localStorage.remoteMapConfig = JSON.stringify(config);
console.log("Config updated: "+localStorage.remoteMapConfig);
// also update config live
remoteMapConfig.movementSpeed = config.movementSpeed;
}
}
})();
var socket = io.connect(document.location.origin);
socket.on('hello', function (data) {
console.log(data);
socket.emit("registerMapRequester", {instanceID: getParameterByName("instanceID")});
socket.on("mapRequesterReady", function(){
setInterval(()=>{
socket.emit("heartbeat"); // send our heartbeat to prevent being assumed dead
},10000);
// load important images then proceed with rendering (and loading more images)
global.spritesheet = new Image();
global.spritesheet.onload = function(){
global.grassBackground = new Image();
global.grassBackground.onload = function(){
requestMapDraw();
}
global.grassBackground.src = "/pictures/grass-1.png";
}
global.spritesheet.src = "/pictures/spritesheet.png";
});
socket.on("displayChunk", function(chunk){
console.log("displayChunk triggered but I can't draw chunks");
});
socket.on("displayEntity", function(entity){
// console.log("Displaying entity "+JSON.stringify(entity));
drawEntity(entity);
});
});
function requestChunk(x,y){
socket.emit('requestChunk', {x:x, y:y, instanceID: getParameterByName("instanceID")});
}
(function(){
let remoteMapLayers = document.querySelectorAll(".remoteMap");
remoteMapLayers.forEach(layer => {
layer.addEventListener('contextmenu', event => event.preventDefault());
layer.width = remoteMapConfig.tileSize * remoteMapConfig.mapSize;
layer.height = remoteMapConfig.tileSize * remoteMapConfig.mapSize;
});
["width", "height"].forEach(style => document.querySelector("#remoteMapContainer").style[style] = remoteMapConfig.tileSize * remoteMapConfig.mapSize + "px");
})();
const canvas = document.querySelector("#remoteMap");
const ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Use WASD to navigate.",10,50);
const selectionCanvas = document.querySelector("#remoteMapSelection");
const selectionCtx = selectionCanvas.getContext("2d");
selectionCtx.font = "30px Arial";
selectionCtx.fillText("Selection layer",10,50);
const backgroundCanvas = document.querySelector("#remoteMapBackground");
const backgroundCtx = backgroundCanvas.getContext("2d");
// map view position, top left corner (or another corner?)
window.playerPosition = {
x:0,
y:0,
}
window.cachePosition = {
x:0,
y:0,
};
function requestMapDraw(){
let xLow = Math.floor(cachePosition.x % remoteMapConfig.tileSize);
let yLow = Math.floor(cachePosition.y % remoteMapConfig.tileSize);
let xHigh = xLow+remoteMapConfig.mapSize;
let yHigh = yLow+remoteMapConfig.mapSize;
for(let x = xLow; x < xHigh; x++){
for(let y = yLow; y < yHigh; y++){
socket.emit("requestEntity", {x, y, instanceID: getParameterByName("instanceID")});
}
}
}
document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
function keyDownHandler(event) {
if(event.keyCode == 39 || event.keyCode == 68) {
rightPressed = true;
}
else if(event.keyCode == 37 || event.keyCode == 65) {
leftPressed = true;
}
if(event.keyCode == 40 || event.keyCode == 83) {
downPressed = true;
}
else if(event.keyCode == 38 || event.keyCode == 87) {
upPressed = true;
}
}
function keyUpHandler(event) {
if(event.keyCode == 39 || event.keyCode == 68) {
rightPressed = false;
}
else if(event.keyCode == 37 || event.keyCode == 65) {
leftPressed = false;
}
if(event.keyCode == 40 || event.keyCode == 83) {
downPressed = false;
}
else if(event.keyCode == 38 || event.keyCode == 87) {
upPressed = false;
}
}
var entityCache = new Array(remoteMapConfig.mapSize);
// populate cache with arrays of arrays
for(let i = 0; i < remoteMapConfig.mapSize; i++){
entityCache[i] = new Array(remoteMapConfig.mapSize);
for(let o = 0; o < remoteMapConfig.mapSize; o++){
entityCache[i][o] = " ";
}
}
// cache navigation functions, for panning (walking, if you will)
const cache = {
walkDown: function walkUp(){
cachePosition.y += remoteMapConfig.tileSize;
for(let i = 0; i < remoteMapConfig.mapSize; i++){
entityCache[i].shift(); // remove leftmost entry
entityCache[i].push(" "); // add new entry on the right
// get data from slaveMapper
let x = cachePosition.x/remoteMapConfig.tileSize + i;
let y = cachePosition.y/remoteMapConfig.tileSize+remoteMapConfig.mapSize-1;
socket.emit("requestEntity", {x, y, instanceID: getParameterByName("instanceID")});
}
},
walkUp: function walkDown(){
cachePosition.y -= remoteMapConfig.tileSize;
for(let i = 0; i < remoteMapConfig.mapSize; i++){
entityCache[i].pop(); // remove rightmost entry
entityCache[i].unshift(" "); // add new entry on the left
// get data from slaveMapper
let x = cachePosition.x/remoteMapConfig.tileSize + i;
let y = cachePosition.y/remoteMapConfig.tileSize;
socket.emit("requestEntity", {x, y, instanceID: getParameterByName("instanceID")});
}
},
walkLeft: function walkLeft(){
cachePosition.x += remoteMapConfig.tileSize;
entityCache.shift();
entityCache.push(new Array(remoteMapConfig.mapSize));
// get data from slaveMapper
// fill in a row on the right side of the screen, that is the bottom of the 1st level array
for(let i = 0; i < remoteMapConfig.mapSize; i++){
let x = cachePosition.x/remoteMapConfig.tileSize + remoteMapConfig.mapSize - 1;
let y = cachePosition.y/remoteMapConfig.tileSize + i;
socket.emit("requestEntity", {x, y, instanceID: getParameterByName("instanceID")});
}
},
walkRight: function walkRight(){
cachePosition.x -= remoteMapConfig.tileSize;
entityCache.pop();
entityCache.unshift(new Array(remoteMapConfig.mapSize));
// get data from slaveMapper
// fill a row on the left side of the screen, that is the top column
for(let i = 0; i < remoteMapConfig.mapSize; i++){
let x = cachePosition.x/remoteMapConfig.tileSize;
let y = cachePosition.y/remoteMapConfig.tileSize + i;
socket.emit("requestEntity", {x, y, instanceID: getParameterByName("instanceID")});
}
}
}
function drawFromCache(){
clear();
let startTime = Date.now()
entityCache.forEach(row => {
row.forEach(doc => {
if(doc && typeof doc == "object"){
drawEntity(doc, true);
}
});
});
}
window.requestAnimationFrame(renderLoop);
var fpsTimings = {
lastFrame: Date.now(),
averageLength: 60,
sum:0,
counter: document.querySelector("#fpsCounter"),
}
var isPaused = false;
window.onblur = function() {
if(localStorage.remoteMapPauseOnBlur == "true"){
isPaused = true;
console.log("paused");
}
}
window.onfocus = function() {
if(isPaused){
isPaused = false;
console.log("unpaused");
window.requestAnimationFrame(renderLoop);
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
window.mousePos = {};
selectionCanvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(selectionCanvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
window.mousePos.x = mousePos.x;
window.mousePos.y = mousePos.y;
}, false);
selectionCanvas.addEventListener("mousedown", function(evt) {
if(evt.which === 1) window.mousePos.clicked = true;
if(evt.which === 3) window.mousePos.rightClicked = true;
// place item in world by sending it with websockets and shit
let tileSize = remoteMapConfig.tileSize;
let entity = {
name: itemSelectorGUI.getItem().name,
position:{
x: Math.floor((playerPosition.x + window.mousePos.x) / tileSize),
y: Math.floor((playerPosition.y + window.mousePos.y) / tileSize),
},
direction: itemSelectorGUI.getItem().direction.toString(),
};
if(evt.which === 1){ // left click to place
console.log(JSON.stringify(entity));
socket.emit("placeEntity", entity);
} else if(evt.which === 3){ // right click to delete
entity.name = "deleted";
socket.emit("placeEntity", entity)
}
// console.log(entity);
});
selectionCanvas.addEventListener("mouseup", function(evt) {
if(evt.which === 1) window.mousePos.clicked = false;
if(evt.which === 3) window.mousePos.rightClicked = false;
});
function renderLoop(){
// render game canvas
let newTimestamp = Date.now();
fpsTimings.sum = fpsTimings.sum / fpsTimings.averageLength * (fpsTimings.averageLength - 1);
let timeSinceLastFrame;
fpsTimings.sum += timeSinceLastFrame = newTimestamp - fpsTimings.lastFrame;
fpsTimings.counter.value = (1000 / (fpsTimings.sum / fpsTimings.averageLength)).toPrecision(4);
fpsTimings.lastFrame = newTimestamp;
if(!isPaused){
let moveSpeed = Number(remoteMapConfig.movementSpeed);
let movement = moveSpeed * timeSinceLastFrame;
// handle movement and requesting new entities
if(upPressed){
console.log("w");
playerPosition.y -= movement;
if(Math.abs((playerPosition.y-cachePosition.y)/remoteMapConfig.tileSize) > 1){
for(let i = 0; i < Math.floor(Math.abs((playerPosition.y-cachePosition.y)/remoteMapConfig.tileSize)); i++){
cache.walkUp();
}
}
}
if(leftPressed){
console.log("a");
playerPosition.x -= movement;
if(Math.abs((playerPosition.x-cachePosition.x)/remoteMapConfig.tileSize) > 1){
for(let i = 0; i < Math.floor(Math.abs((playerPosition.x-cachePosition.x)/remoteMapConfig.tileSize)); i++){
cache.walkRight();
}}
}
if(downPressed){
console.log("s");
playerPosition.y += movement;
if(Math.abs((playerPosition.y-cachePosition.y)/remoteMapConfig.tileSize) > 1){
for(let i = 0; i < Math.floor(Math.abs((playerPosition.y-cachePosition.y)/remoteMapConfig.tileSize)); i++){
cache.walkDown();
}}
}
if(rightPressed){
console.log("d");
let oldPos = playerPosition.x;
playerPosition.x += movement;
if(Math.abs((playerPosition.x-cachePosition.x)/remoteMapConfig.tileSize) > 1){
for(let i = 0; i < Math.floor(Math.abs((playerPosition.x-cachePosition.x)/remoteMapConfig.tileSize)); i++){
cache.walkLeft();
}}
}
// draw map
drawFromCache();
// queue next tick
window.requestAnimationFrame(renderLoop);
}
// render selection canvas
let mousePosition = window.mousePos;
if(mousePosition && mousePosition.x){
// make a box around the mouse cursor
selectionCtx.beginPath();
selectionCtx.lineWidth = remoteMapConfig.tileSize / 16;
selectionCtx.strokeStyle="yellow";
if(mousePosition.clicked) selectionCtx.strokeStyle = "red";
if(mousePosition.rightClicked) selectionCtx.strokeStyle = "blue";
let tileSize = remoteMapConfig.tileSize
let halfTile = tileSize / 2;
let tilePosition = { // position in world coordinates (same as used by factorio)
x: Math.floor((playerPosition.x + mousePosition.x) / tileSize),
y: Math.floor((playerPosition.y + mousePosition.y) / tileSize),
}
// Long thing to correct for offset between playerPosition, cachePosition (tile grid) and mouse position and draw the box so it aligns with tiles.
selectionCtx.rect(tilePosition.x * tileSize - playerPosition.x, tilePosition.y * tileSize - playerPosition.y, tileSize, tileSize);
selectionCtx.stroke();
}
// render background canvas
let dw = 1024 / 32 * remoteMapConfig.tileSize;
let dh = 64 / 32 * remoteMapConfig.tileSize;
// 0-dw and x < ?? + dw is to make sure we draw well outside the canvas on both sides to avoid ugly gfx
for(let x = 0-dw; x < remoteMapConfig.tileSize * remoteMapConfig.mapSize + dw; x += dw){
for(let y = 0-dh; y < remoteMapConfig.tileSize * remoteMapConfig.mapSize + dh; y += dh){
let dx = x - playerPosition.x % dw;
let dy = y - playerPosition.y % dh;
if(global.grassBackground && isImageOk(global.grassBackground)) backgroundCtx.drawImage(global.grassBackground, 0, 64, 1024, 64, dx, dy, dw, dh);
}
}
}
var entityImages = {}; // cache to store images and details about entities, populated by drawEntity();
window.logEntCache = function(){console.log(entityCache)}
function drawEntity(entity, dontCache){
if(entity.x !== undefined && entity.y !== undefined){
if(!dontCache){
// cache entity for later draws (like panning)
if(entity.x - cachePosition.x/remoteMapConfig.tileSize >= 0 && entity.x - cachePosition.x/remoteMapConfig.tileSize < remoteMapConfig.mapSize && entity.y - cachePosition.y/remoteMapConfig.tileSize >= 0 && entity.y - cachePosition.y/remoteMapConfig.tileSize < remoteMapConfig.mapSize){
if(entity.entity){
entityCache[entity.x - cachePosition.x/remoteMapConfig.tileSize][entity.y - cachePosition.y/remoteMapConfig.tileSize] = entity;
} else {
// delete this entity because we just heard the tile is empty and stuff
entityCache[entity.x - cachePosition.x/remoteMapConfig.tileSize][entity.y - cachePosition.y/remoteMapConfig.tileSize] = " ";
}
}
}
if(entity.entity && entity.entity.name && typeof entity.entity.name == "string"){
let name = entity.entity.name;
if(!entityImages[name]){
console.log("Downloading image "+name);
// download the entityImages and add stuff to queue
entityImages[name] = {
img: new Image(),
queue: [],
loaded: false,
};
entityImages[name].draw = function(entity){
if(this.loaded){
let name = entity.entity.name;
let image, sprWidth, sprHeight, offLeft, offTop, size, offsetX, offsetY;
let flipX = false, flipY = false;
let rotation = 0;
// check hardcoded entity draw rules for specifics (otherwise draw icon as 1x1 entity with rotation if specified)
if(entityDrawRules[name] && (entityDrawRules[name].positionOffset || entityDrawRules[name].spritesheet)){
let rules = entityDrawRules[name]
if(rules.positionOffset){
offsetX = rules.positionOffset.x;
offsetY = rules.positionOffset.y;
}
if(rules.sizeInTiles){
size = {
x: remoteMapConfig.tileSize * rules.sizeInTiles.x,
y: remoteMapConfig.tileSize * rules.sizeInTiles.y,
};
}
if(rules.spritesheet && Array.isArray(rules.spritesheet)){
let dir = Number(entity.entity.rot || 0);
// 2 animated sprites, we will need to flip it for rotations.
if(rules.spritesheet.length == 2){
let spritesheetAnim = dir / 2 % 2;
let animationStage = Math.floor(Date.now()/16) % rules.spritesheet[spritesheetAnim].spritesheet.length;
try{
sprWidth = rules.spritesheet[spritesheetAnim].spritesheet[animationStage].frame.w;
sprHeight = rules.spritesheet[spritesheetAnim].spritesheet[animationStage].frame.h;
offLeft = rules.spritesheet[spritesheetAnim].spritesheet[animationStage].frame.x;
offTop = rules.spritesheet[spritesheetAnim].spritesheet[animationStage].frame.y;
} catch(e){
// console.log(name)
// console.log(rules.spritesheet[spritesheetAnim].spritesheet)
}
image = global.spritesheet;
// handle rotation (not handled by generic handler because we have to do flips and special stuff)
if(dir == 4){
// rotation = (dir/2)*90
// console.log("rotating")
flipY = true;
} else if(dir == 6){
flipX = true;
// rotation = ((dir+2)/2)*90+180 // this formula is terrible, don't try to repair, there is no sense to it
}
if(rules.spritesheet[spritesheetAnim].positionOffset){
offsetX = rules.spritesheet[spritesheetAnim].positionOffset.x;
offsetY = rules.spritesheet[spritesheetAnim].positionOffset.y;
}
if(rules.spritesheet[spritesheetAnim].sizeInTiles){
size = {
x: remoteMapConfig.tileSize * rules.spritesheet[spritesheetAnim].sizeInTiles.x,
y: remoteMapConfig.tileSize * rules.spritesheet[spritesheetAnim].sizeInTiles.y,
};
}
} else {
// correct for whether we have 1, 4 or 8 directions
let spriteSheetRotIndex = dir / (8 / rules.spritesheet.length);
if(rules.spritesheet.length > 8) {
// apparently this entity has more than 8 directions. That isn't supported.
// therefore we can conclude that they are instead intended as animation frames.
// That is why we treat them as animation frames.
spriteSheetRotIndex = Math.floor(Date.now()/32) % rules.spritesheet.length;
} else if(rules.spritesheet[spriteSheetRotIndex].spritesheet.length){
var animationStage = Math.floor(Date.now()/16) % rules.spritesheet[spriteSheetRotIndex].spritesheet.length;
var usesAnimation = true;
} else {
var usesAnimation = false;
}
if(usesAnimation){
try{
sprWidth = rules.spritesheet[spriteSheetRotIndex].spritesheet[animationStage].frame.w;
sprHeight = rules.spritesheet[spriteSheetRotIndex].spritesheet[animationStage].frame.h;
offLeft = rules.spritesheet[spriteSheetRotIndex].spritesheet[animationStage].frame.x;
offTop = rules.spritesheet[spriteSheetRotIndex].spritesheet[animationStage].frame.y;
}catch(e){} // TODO throws error due to yellow belt rendering
} else {
sprWidth = rules.spritesheet[spriteSheetRotIndex].spritesheet.frame.w;
sprHeight = rules.spritesheet[spriteSheetRotIndex].spritesheet.frame.h;
offLeft = rules.spritesheet[spriteSheetRotIndex].spritesheet.frame.x;
offTop = rules.spritesheet[spriteSheetRotIndex].spritesheet.frame.y;
}
image = global.spritesheet;
if(rules.spritesheet[spriteSheetRotIndex].positionOffset){
offsetX = rules.spritesheet[spriteSheetRotIndex].positionOffset.x;
offsetY = rules.spritesheet[spriteSheetRotIndex].positionOffset.y;
}
if(rules.spritesheet[spriteSheetRotIndex].sizeInTiles){
size = {
x: remoteMapConfig.tileSize * rules.spritesheet[spriteSheetRotIndex].sizeInTiles.x,
y: remoteMapConfig.tileSize * rules.spritesheet[spriteSheetRotIndex].sizeInTiles.y,
};
}
if(rules.spritesheet[spriteSheetRotIndex].flip){
let flip = rules.spritesheet[spriteSheetRotIndex].flip;
if(flip == "x") flipX = true;
if(flip == "y") flipY = true;
}
}
} else if(rules.spritesheet){
sprWidth = rules.spritesheet.frame.w;
sprHeight = rules.spritesheet.frame.h;
offLeft = rules.spritesheet.frame.x;
offTop = rules.spritesheet.frame.y;
image = global.spritesheet;
}
} else {
offsetX = 0, offsetY = 0;
size = {
x:remoteMapConfig.tileSize, y: remoteMapConfig.tileSize,
};
}
let xPos = ((entity.x + offsetX) * remoteMapConfig.tileSize) - playerPosition.x;
let yPos = ((entity.y + offsetY) * remoteMapConfig.tileSize) - playerPosition.y;
if(entity.entity.rot && !isNaN(Number(entity.entity.rot)) && !(entityDrawRules[name] && Array.isArray(entityDrawRules[name].spritesheet))){
let rules = entityDrawRules[name];
if(rules && rules.rotOffset){
rotation = ((entity.entity.rot * 45) + entityDrawRules[name].rotOffset);
} else {
rotation = entity.entity.rot * 45;
}
}
if(!image) image = entityImages[name].img;
// if(name == "oil-refinery") console.log(offsetX)
drawImageWithRotation(ctx, image, xPos, yPos, size.x, size.y, rotation%360, sprWidth, sprHeight, offLeft, offTop, flipX, flipY);
//console.log("Drawing "+name+" at X: "+xPos+", Y: "+yPos+" with with rotation "+rotation);
} else {
// we are waiting for the image to load, push the task to our queue. It will be processed once the image loads.
this.queue.push(entity);
}
}
let imageLoaded = function(){
// process queue and display
console.log("Image loaded!");
entityImages[name].loaded = true;
entityImages[name].queue.forEach(entity => {
entityImages[name].draw(entity);
});
entityImages[name].queue = [];
}
entityImages[name].queue.push(entity);
entityImages[name].img.onload = imageLoaded()
if(entityDrawRules[name] && entityDrawRules[name].spritesheet){
// imageLoaded();
} else entityImages[name].img.src = getImageFromName(name);
} else {
// console.log("Already got image, drawing")
entityImages[name].draw(entity);
}
} else {
// we got an empty coordinate pair, that usually means this tile was occupied before but is empty now
console.log("Clearing at X: "+entity.x+", Y: "+entity.y);
ctx.clearRect((entity.x + playerPosition.x/remoteMapConfig.tileSize) * remoteMapConfig.tileSize, (entity.y + playerPosition.y/remoteMapConfig.tileSize) * remoteMapConfig.tileSize, remoteMapConfig.tileSize, remoteMapConfig.tileSize);
}
} else {
console.log(entity);
throw new Error("drawEntity on entity without x and y coordinates");
}
}
function clear(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
selectionCtx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
backgroundCtx.clearRect(0, 0, backgroundCanvas.width, backgroundCanvas.height);
}
// setInterval(()=>console.log(entityDrawRules),5000);
-85
View File
@@ -1,85 +0,0 @@
export class itemSelector {
constructor(containerSelector, entities){
this.containerSelector = containerSelector;
this.container = document.querySelector(containerSelector);
if(!this.container) throw new Error("Could not find container "+container);
this.entities = entities;
this.direction = 0;
// populate container
let cont = this.container;
let HTML = "";
HTML += "<div class='header'>";
HTML += "<h2>Item selection</h2>";
HTML += "</div>";
HTML += "<div class='itemSelector'>";
HTML += "<span>Name: </span>";
HTML += "<select class='blackText'>";
this.entities.forEach(entity => HTML += "<option value='"+entity.name+"'>"+entity.name+"</option>");
HTML += "</select>";
HTML += "</div>";
// direction selector
HTML += "<div id='directionSelector'>";
HTML += "<h2>Direction: </h2>";
HTML += "<h2 id='directionDisplay'>"+this.directionToCardinal(0)+"</h2>"
HTML += "<p>Press R to rotate</p>";
HTML += "</div>";
// write styles
let styles = {
".header > h2":{
color:"white",
},
".blackText":{
color:"black",
},
".blackText > option":{
color:"black",
}
}
// turn style object into style tag
HTML += "<style>";
for(let style in styles){
HTML += containerSelector+" "+style+"{";
for(let styleName in styles[style]){
let styleValue = styles[style][styleName];
HTML += styleName+":"+styleValue+";";
}
HTML += "}";
}
cont.innerHTML += HTML + "</style>";
// handle direction keyboard event
Mousetrap.bind('r', ()=>this.rotate());
}
directionToCardinal(dir){
if(dir == 0){
return "north";
} else if(dir == 1){
return "north-east";
} else if(dir == 2){
return "east";
} else if(dir == 3){
return "south-east";
} else if(dir == 4){
return "south";
} else if(dir == 5){
return "south-west";
} else if(dir == 6){
return "west";
} else if(dir == 7){
return "north-west";
}
}
rotate(){
this.direction = (this.direction + 2) % 8;
// update display
document.querySelector("#directionDisplay").innerHTML = this.directionToCardinal(this.direction);
}
getItem(){
let name = document.querySelector(this.containerSelector+" > .itemSelector > select").value;
let direction = this.direction;
return {name, direction};
}
}
-14
View File
@@ -17,20 +17,6 @@ setTimeout(function() {
HTML += "<a href='nodeDetails?instanceID="+slaveData[key].unique+"'><h2>" + slaveData[key].instanceName + "</h2></a><p>ID: " + slaveData[key].unique + "</p><p>Last seen: "+seenDate+"</p><p>Online players: "+slaveData[key].playerCount+"</p><p>IP: "+slaveData[key].publicIP +":"+ slaveData[key].serverPort+"</p>"
HTML += "<p>Host: "+slaveData[key].mac+"</p>";
// detect if remoteMap mod is installed, if it is we want to show the link for it
let hasRemoteMap = false;
if(slaveData[key].mods){ // not all instances have mods apparently
slaveData[key].mods.forEach(mod => {
console.log(mod.modName);
if(mod.modName.includes("remoteMap")){
hasRemoteMap = true; // we are still doing the logic on the outside, in case there are multiple instances of remoteMap installed....
}
});
}
if(hasRemoteMap){
HTML += "<a href='/remoteMap?instanceID="+slaveData[key].unique+"'>Remote map</a>"
}
HTML += "<br><p>Graph tools:</p>";
HTML += "<button style='width:100px;' onclick='hideAllDatasets(\"" + slaveData[key].unique + "\")\'>Hide all</button>";
HTML += "<button style='width:100px;' onclick='showAllDatasets(\"" + slaveData[key].unique + "\")\'>Show all</button>";