mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
157 lines
10 KiB
JavaScript
157 lines
10 KiB
JavaScript
const objectOps = require("../../lib/objectOps.js");
|
|
const needle = require("needle");
|
|
const pluginConfig = require("./config")
|
|
const isJson = require("./isJson")
|
|
|
|
// returns JS object, throws if there are syntax errors in input string
|
|
function parseJsString(string){
|
|
// eval because my lua is writing a JS object instead of traditional JSON
|
|
// this was done because I hate escaping strings and there are more quotes
|
|
// in JSON than JS objects.
|
|
|
|
// since eval is unsafe, maybe use https://www.npmjs.com/package/eval-sanitizer
|
|
if(string.includes("require") || string.includes(";") || string.includes("eval")){
|
|
throw "parseJsString might have gotten something that could be a xss attempt";
|
|
}
|
|
let inventory = "";
|
|
eval("inventory = " + string);
|
|
/*console.log(string)
|
|
console.log(inventory)*/
|
|
return inventory;
|
|
}
|
|
function handleInventory(json, config, callback){
|
|
/*
|
|
json is one of these two samples
|
|
{"players":{"1":{"inventory":{"stone":12,"iron-ore":120,"raw-wood":10,"iron-plate":8,"steel-plate":480},"requestSlots":{}}}}
|
|
{"exports":{"1":[{"name":"iron-ore","count":0},{"name":"steel-plate","count":0}]}}
|
|
|
|
we want to seperate players, parse their json and compare to request slots
|
|
then ask master for the difference
|
|
we must then prepare it all and inject it into players inventories with lua before
|
|
the next json report arrives to avoid duplicating orders
|
|
*/
|
|
if(json && typeof json != "string" && typeof json == "object"){
|
|
let exports = {};
|
|
|
|
// this is an inventory report, check whats missing and request from master
|
|
// {"players":{"1":{"inventory":{"stone":12,"iron-ore":120,"raw-wood":10,"iron-plate":8,"steel-plate":480},"requestSlots":{}}}}
|
|
if(json.players){
|
|
let playerNames = Object.keys(json.players);
|
|
for(let i = 0; i < playerNames.length; i++) {
|
|
// haha, this turned into bit of a mess didn't it?
|
|
let playerInv = json.players[playerNames[i]];
|
|
// create a copy of player.requestSlots
|
|
let toRequest = objectOps.deepclone(playerInv.requestSlots);
|
|
let inventory = playerInv.inventory;
|
|
let itemsToConfirm = Object.keys(toRequest).length;
|
|
// create a place to store the object we have confirmed for importing
|
|
let confirmedItems = {};
|
|
let collectStacks = function(stack){
|
|
itemsToConfirm--;
|
|
if(stack){
|
|
// because of the way we collect data in a keyed JSON object, this first part of the IF cannot happen.
|
|
/* istanbul ignore next */
|
|
if(confirmedItems[stack.name] && confirmedItems[stack.name] > 0){
|
|
confirmedItems[stack.name] += stack.count;
|
|
} else {
|
|
confirmedItems[stack.name] = stack.count;
|
|
}
|
|
}
|
|
if(itemsToConfirm == 0 && Object.keys(confirmedItems).length > 0){
|
|
// return LUA
|
|
callback(insertItemsFromObject(confirmedItems, playerNames[i]));
|
|
}
|
|
}
|
|
// subtract items already in inventory
|
|
Object.keys(playerInv.requestSlots).forEach(function(key){
|
|
// if this item in inventory is also in a request slot, subtract invCount from requestCount
|
|
if(inventory[key]){
|
|
toRequest[key] -= inventory[key];
|
|
}
|
|
// if the difference is more than 0, request item from master
|
|
if(toRequest[key] > 0){
|
|
let request = {
|
|
name:key,
|
|
count:toRequest[key],
|
|
}
|
|
//console.log("Requesting: "+JSON.stringify(request));
|
|
// request the difference from master
|
|
needle.post(config.masterIP + ":" + config.masterPort + '/api/remove', request, {json:true,headers: {'x-access-token': config.masterAuthToken}}, function (err, response, body) {
|
|
if (!err && response && response.body && (typeof response.body == "object" || isJson(response.body))) {
|
|
// confirmed orders, already removed from master inventory
|
|
//response.body.name: response.body.count
|
|
if(typeof response.body == "string") response.body = JSON.parse(response.body);
|
|
let stack = {name:response.body.name,count:Number(response.body.count)}
|
|
collectStacks(stack);
|
|
} else {
|
|
collectStacks(false);
|
|
}
|
|
});
|
|
} else {
|
|
collectStacks(false);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
// {"exports":{"1":[{"name":"iron-ore","count":0},{"name":"steel-plate","count":0}]}}
|
|
// this is a report of stuff we didn't have space for, send back to master
|
|
if(json.exports){
|
|
// loop over players (normally only one, but whatever)
|
|
Object.keys(json.exports).forEach(function(playerName){
|
|
// loop over simpleItemStacks to export
|
|
let stackArray = json.exports[playerName];
|
|
for(let i = 0; i < stackArray.length; i++){
|
|
if(stackArray[i].count > 0){
|
|
// console.log("Returning overflow: " + JSON.stringify(stackArray[i]));
|
|
needle.post(config.masterIP + ":" + config.masterPort + '/api/place', stackArray[i], {headers: {'x-access-token': config.masterAuthToken}}, function (err, resp, body) {
|
|
// console.log(body);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} else return false; // inventory is falsey or a string
|
|
}
|
|
function insertItemsFromObject(confirmedItems, playerName){
|
|
// expeced input
|
|
// {["iron-plate"]:100, coal:20}
|
|
// make lua table
|
|
// we gotta construct a string because I can't find any nice library for this
|
|
if(playerName && confirmedItems){
|
|
if(typeof playerName != "string") {
|
|
throw "playerName is: '"+typeof playerName+"' instead of string!";
|
|
}
|
|
let itemTable = "{";
|
|
Object.keys(confirmedItems).forEach(function(name){
|
|
let count = confirmedItems[name];
|
|
if(count > 0){
|
|
itemTable += '["'+name+'"]='+Math.floor(count)+',';
|
|
}
|
|
});
|
|
itemTable += "}";
|
|
let outputFile = pluginConfig.scriptOutputFileSubscription;
|
|
// a="'+players[i]+'"
|
|
// b='+itemTable+'
|
|
return '/silent-command local a="'+playerName+'"local b='+itemTable+'local c={}if game.players[a]and game.players[a].connected then local d='+"'"+'{"exports":{"'+"'"+'..a..'+"'"+'":['+"'"+'local e=false;for f,g in pairs(b)do local h=game.players[a].insert{name=f,count=g}if e then d=d..'+"'"+','+"'"+'else e=true end;d=d..'+"'"+'{"name":"'+"'"+'..f..'+"'"+'","count":'+"'"+'..g-h..'+"'"+'}'+"'"+'end;d=d..'+"'"+']}}'+"'"+'game.write_file("'+outputFile+'",d,true,0)end';
|
|
}
|
|
}
|
|
function pollInventories(outputFile){
|
|
// console.log("/silent-command "+'local a=game.players["Danielv123"].get_inventory(defines.inventory.player_main).get_contents()local b=game.players["Danielv123"].get_quickbar().get_contents()local c={}local d="{inventory:{"for e,f in pairs(a)do d=d.."['+"'"+'"..e.."'+"'"+']:"..f..","end;for e,f in pairs(b)do d=d.."['+"'"+'"..e.."'+"'"+']:"..f..","end;d=d.."},requestSlots:{"for e,f in pairs(c)do d=d.."['+"'"+'"..e.."'+"'"+']:"..f..","end;d=d.."}}"game.write_file("'+pluginConfig.scriptOutputFileSubscription+'",d)');
|
|
// console.log("Running inventory LUA")
|
|
//console.log("/silent-command "+'local a=game.players["Danielv123"].get_inventory(defines.inventory.player_main).get_contents()local b=game.players["Danielv123"].get_quickbar().get_contents()local c={}for d=1,game.players["Danielv123"].force.character_logistic_slot_count do c[d]=game.players["Danielv123"].character.get_request_slot(d)end;local e="{inventory:{"for f,g in pairs(a)do e=e.."['+"'"+'"..f.."'+"'"+']:"..g..","end;for f,g in pairs(b)do e=e.."['+"'"+'"..f.."'+"'"+']:"..g..","end;e=e.."},requestSlots:{"for f,g in pairs(c)do e=e.."['+"'"+'"..g["name"].."'+"'"+']:"..g["count"]..", "end;e=e.."}}"game.write_file("'+pluginConfig.scriptOutputFileSubscription+'",e)')
|
|
// console.log("/silent-command "+'local a="{"for b,c in pairs(game.players)do local d=game.players[b].get_inventory(defines.inventory.player_main).get_contents()local e=game.players[b].get_quickbar().get_contents()local f={}for g=1,game.players[b].force.character_logistic_slot_count do f[g]=game.players[b].character.get_request_slot(g)end;a=a..b..":{inventory:{"for h,i in pairs(d)do a=a.."['+"'"+'"..h.."'+"'"+']:"..i..","end;for h,i in pairs(e)do a=a.."['+"'"+'"..h.."'+"'"+']:"..i..","end;a=a.."},requestSlots:{"for h,i in pairs(f)do a=a.."['+"'"+'"..i["name"].."'+"'"+']:"..i["count"]..", "end;a=a.."}},"end;a=a.."}"game.write_file("'+pluginConfig.scriptOutputFileSubscription+'",a)')
|
|
//return "/silent-command "+'local a="{"for b,c in pairs(game.players)do if c.connected then local d=game.players[b].get_inventory(defines.inventory.player_main).get_contents()local e=game.players[b].get_quickbar().get_contents()local f={}for g=1,game.players[b].force.character_logistic_slot_count do f[g]=game.players[b].character.get_request_slot(g)end;a=a..b..":{inventory:{"for h,i in pairs(d)do a=a.."['+"'"+'"..h.."'+"'"+']:"..i..","end;for h,i in pairs(e)do a=a.."['+"'"+'"..h.."'+"'"+']:"..i..","end;a=a.."},requestSlots:{"for h,i in pairs(f)do a=a.."['+"'"+'"..i["name"].."'+"'"+']:"..i["count"]..", "end;a=a.."}},"end end;a=a.."}"game.write_file("'+outputFile+'",a)'
|
|
return '/silent-command '+'local a='+"'"+'{"players":{'+"'"+'local b=false;for c,d in pairs(game.players)do if d.connected and d.character then if b then a=a..'+"'"+','+"'"+'else b=true end;local e=game.players[c].get_inventory(defines.inventory.player_main).get_contents()local f=game.players[c].get_quickbar().get_contents()local g={}local z={}for j,k in pairs(e)do if z[j] ~= nil then z[j] = z[j] + k else z[j] = k end end for j,k in pairs(f)do if z[j] ~= nil then z[j] = z[j] + k else z[j] = k end end for h=1,game.players[c].force.character_logistic_slot_count do g[h]=game.players[c].character.get_request_slot(h)end;a=a..'+"'"+'"'+"'"+'..c..'+"'"+'":{"inventory":{'+"'"+'local i=false;for j,k in pairs(z)do if i then a=a..'+"'"+','+"'"+'else i=true end;a=a..'+"'"+'"'+"'"+'..j..'+"'"+'":'+"'"+'..k end;a=a..'+"'"+'},"requestSlots":{'+"'"+'i=false;for j,k in pairs(g)do if i then a=a..'+"'"+','+"'"+'else i=true end;a=a..'+"'"+'"'+"'"+'..k['+"'"+'name'+"'"+']..'+"'"+'":'+"'"+'..k['+"'"+'count'+"'"+']end;a=a..'+"'"+'}}'+"'"+'end end;a=a.."}}"game.write_file("'+outputFile+'",a,true,0)'
|
|
/*
|
|
needle.post(config.masterIP+':'+config.masterPort+'/api/editSlaveMeta', {instanceID: config.unique, password: config.clientPassword, meta: {UPS:UPS}}, function(err, resp) {
|
|
// success?
|
|
});
|
|
*/
|
|
}
|
|
|
|
module.exports = {
|
|
handleInventory: handleInventory,
|
|
parseJsString: parseJsString,
|
|
pollInventories: pollInventories,
|
|
insertItemsFromObject: insertItemsFromObject,
|
|
} |