diff --git a/master.js b/master.js index f667f27a..e58cb344 100644 --- a/master.js +++ b/master.js @@ -659,14 +659,21 @@ class mapRequester { 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) + slaveMappers[instanceID].socket.emit("getChunk", loc); } }); this.socket.on("requestEntity", req => { 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) + slaveMappers[instanceID].socket.emit("getEntity", req); + } + }); + this.socket.on("placeEntity", req => { + req.requesterID = this.requesterID; + let instanceID = req.instanceID || this.instanceID; + if(slaveMappers[instanceID]){ + slaveMappers[instanceID].socket.emit("placeEntity", req); } }); } diff --git a/sharedPlugins/remoteMap/index.js b/sharedPlugins/remoteMap/index.js index 72403789..f13d7771 100644 --- a/sharedPlugins/remoteMap/index.js +++ b/sharedPlugins/remoteMap/index.js @@ -51,9 +51,45 @@ class remoteMap { this.messageInterface("socket.getEntity triggered called with invalid parameters"); } }); + // both placing and deleting entities via the web interface + this.socket.on("placeEntity", req => { + // game.player.surface.create_entity{name="small-ship-wreck", position={game.player.position.x-2, game.player.position.y+1}, direction=..., force=...} + console.log("placing "+JSON.stringify(req)); + if(req.name && typeof req.name == "string" && req.position && Number(req.position.x) && Number(req.position.y)){ + if(req.name == "deleted"){ // {{'+req.position.x+','+req.position.y+'},{'+req.position.x+','+req.position.y+'}} + this.messageInterface('/silent-command local toDelete = game.surfaces[1].find_entities({{'+req.position.x+','+req.position.y+'},{'+(req.position.x+1)+','+(req.position.y+1)+'}}) for i, entity in pairs(toDelete) do entity.die() end'); + // this position is now empty, delete whatever was there from DB + // this.deleteEntity(req.position.x, req.position.y); + } else { + let command = '/silent-command game.surfaces[1].create_entity{name="'+req.name+'", position={'+Number(req.position.x)+', '+Number(req.position.y)+'}, force="neutral"' + if(req.direction) command += ', direction='+req.direction; + command += '}'; + this.messageInterface(command); // execute command + + // add entity to the chunkStore database because create_entity does not trigger any events + let name = req.name; + let entity = {name}; + if(req.direction){ + entity.direction = req.direction; + } + this.addEntity(req.position.x, req.position.y, entity); + } + } + }); this.messageInterface("/silent-command game.print('"+moduleConfig.name+" version "+moduleConfig.version+" enabled')"); } + addEntity(x,y,entity){ // add entity to database + this.chunkMap.setEntity(Number(x), Number(y), entity).then(data => { + this.messageInterface("Added "+entity.name+" to data "+Number(x)+", "+Number(y)); + }).catch((err)=>this.messageInterface(err)); + } + deleteEntity(x,y){ // remove entity from database + // this position is now empty, delete whatever was there from DB + this.chunkMap.setEntity(x, y, "delete this entity").then(() => { + this.messageInterface("Deleted data "+x+", "+y); + }).catch((err)=>this.messageInterface(err)); + } scriptOutput(data){ if(data){ this.messageInterface(data); @@ -70,9 +106,7 @@ class remoteMap { if(xPos && yPos && name){ if(name == "deleted"){ // this position is now empty, delete whatever was there from DB - this.chunkMap.setEntity(xPos, yPos, "delete this entity").then(() => { - this.messageInterface("Deleted data "+xPos+", "+yPos); - }).catch((err)=>this.messageInterface(err)); + this.deleteEntity(xPos, yPos); } else { let entity = {name}; for(let i = 3; i < data.length; i++){ @@ -82,9 +116,10 @@ class remoteMap { } } // save this entity in the database - this.chunkMap.setEntity(xPos, yPos, entity).then(data => { + this.addEntity(xPos, yPos, entity); + /* this.chunkMap.setEntity(xPos, yPos, entity).then(data => { this.messageInterface("Added "+name+" to data "+xPos+", "+yPos); - }).catch((err)=>this.messageInterface(err)); + }).catch((err)=>this.messageInterface(err)); */ } } diff --git a/static/lib/entityDrawRules.js b/static/lib/entityDrawRules.js index 007c63f1..eff37009 100644 --- a/static/lib/entityDrawRules.js +++ b/static/lib/entityDrawRules.js @@ -31,7 +31,7 @@ export var entityDrawRules = { }, positionOffset: { x:-0.8, - y:-1.5, + y:-1.7, }, }, "centrifuge": { @@ -67,7 +67,7 @@ for(let i = 1; i <= 3; i++){ }, positionOffset: { x:-1.4, - y:-0.9, + y:-1.2, }, } // template3x3entity; @@ -125,7 +125,7 @@ for(let i = 1; i <= 3; i++){ x:1.2,y:1.6, }, positionOffset: { - x:0,y:0, + x:0,y:-0.2, } } }); diff --git a/static/remoteMap.html b/static/remoteMap.html index 8b58d8b6..06c96f74 100644 --- a/static/remoteMap.html +++ b/static/remoteMap.html @@ -9,14 +9,14 @@ <%- include("sidebar.html") %>

remoteMap

-
- - +
+ +
-
+
-
+

Map size: (default 32)

Tile size: (default 8)

FPS:

diff --git a/static/remoteMap.js b/static/remoteMap.js index ea551d6a..e5dd56ba 100644 --- a/static/remoteMap.js +++ b/static/remoteMap.js @@ -1,14 +1,34 @@ /** 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. */ - +console.log(":)") /// ES6 imports // rules for how entities are drawn (sizes, offset etc) import {entityDrawRules} from "./lib/entityDrawRules.js"; import {getParameterByName, drawImageWithRotation} 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"} +]); + if(!localStorage.remoteMapConfig || localStorage.remoteMapConfig == "[object Object]"){ localStorage.remoteMapConfig = JSON.stringify({ mapSize: 32, @@ -92,6 +112,7 @@ function requestChunk(x,y){ (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; }); @@ -259,12 +280,37 @@ function getMousePos(canvas, evt) { y: evt.clientY - rect.top }; } -window.mousePos; +window.mousePos = {}; selectionCanvas.addEventListener('mousemove', function(evt) { var mousePos = getMousePos(selectionCanvas, evt); var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y; - window.mousePos = mousePos; + window.mousePos.x = mousePos.x; + window.mousePos.y = mousePos.y; }, false); +selectionCanvas.addEventListener("mousedown", function(evt) { + if(evt.which === 1) window.mousePos.clicked = 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), + }, + }; + 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; +}); function renderLoop(){ // render game canvas let newTimestamp = Date.now(); @@ -319,15 +365,20 @@ function renderLoop(){ // render selection canvas let mousePosition = window.mousePos; - if(mousePosition){ + if(mousePosition && mousePosition.x){ // make a box around the mouse cursor selectionCtx.beginPath(); selectionCtx.lineWidth = remoteMapConfig.tileSize / 8; selectionCtx.strokeStyle="yellow"; + if(mousePosition.clicked) selectionCtx.strokeStyle = "red"; let tileSize = remoteMapConfig.tileSize let halfTile = tileSize / 2; + let tilePosition = { + 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(mousePosition.x - mousePosition.x % tileSize + playerPosition.x % tileSize, mousePosition.y - mousePosition.y % tileSize - playerPosition.y % tileSize, tileSize, tileSize); + selectionCtx.rect(mousePosition.x - mousePosition.x % tileSize - playerPosition.x % tileSize, mousePosition.y - mousePosition.y % tileSize - playerPosition.y % tileSize, tileSize, tileSize); selectionCtx.stroke(); } } diff --git a/static/remoteMap/itemSelection.js b/static/remoteMap/itemSelection.js new file mode 100644 index 00000000..4e7baa13 --- /dev/null +++ b/static/remoteMap/itemSelection.js @@ -0,0 +1,50 @@ +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; + + // populate container + let cont = this.container; + let HTML = ""; + HTML += "
"; + HTML += "

Item selection

"; + HTML += "
"; + HTML += "
"; + HTML += "Name: "; + HTML += ""; + HTML += "
"; + + // write styles + let styles = { + ".header > h2":{ + color:"white", + }, + ".blackText":{ + color:"black", + }, + ".blackText > option":{ + color:"black", + } + } + + // turn style object into style tag + HTML += ""; + } + getItem(){ + let name = document.querySelector(this.containerSelector+" > .itemSelector > select").value; + return {name}; + } +} \ No newline at end of file diff --git a/static/style.css b/static/style.css index 2b026e69..4ac61394 100644 --- a/static/style.css +++ b/static/style.css @@ -271,4 +271,7 @@ input:checked + .slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); +} +canvas { + -webkit-transform:translateZ(0) } \ No newline at end of file