From 98c6795f8f7429293efe55e19ec316318a90264e Mon Sep 17 00:00:00 2001 From: TechnoStrife Date: Sun, 14 Jul 2019 23:29:15 +0300 Subject: [PATCH] Make researchSync work for any research on any node --- sharedPlugins/researchSync/dumpResearch.lua | 10 +- sharedPlugins/researchSync/index.js | 258 ++++++++++++------ sharedPlugins/researchSync/index.spec.js | 6 +- sharedPlugins/researchSync/updateProgress.lua | 28 ++ 4 files changed, 208 insertions(+), 94 deletions(-) create mode 100644 sharedPlugins/researchSync/updateProgress.lua diff --git a/sharedPlugins/researchSync/dumpResearch.lua b/sharedPlugins/researchSync/dumpResearch.lua index e7e43cf0..178365fc 100644 --- a/sharedPlugins/researchSync/dumpResearch.lua +++ b/sharedPlugins/researchSync/dumpResearch.lua @@ -1,11 +1,19 @@ local data = {}; +local force = game.forces["player"]; -for _, tech in pairs(game.forces["player"].technologies) do +for _, tech in pairs(force.technologies) do + local progress; + if tech == force.current_research then + progress = force.research_progress + else + progress = force.get_saved_technology_progress(tech.name); + end local tech_data = { tech.name, tostring(tech.researched), tostring(tech.level), + tostring(progress), } tech_data = table.concat(tech_data, ':') table.insert(data, tech_data); diff --git a/sharedPlugins/researchSync/index.js b/sharedPlugins/researchSync/index.js index 7ab9c488..c1fb9528 100644 --- a/sharedPlugins/researchSync/index.js +++ b/sharedPlugins/researchSync/index.js @@ -6,24 +6,22 @@ function format_tech(tech) { } -function log_tech_unlocking(key, current, prev) { - console.log( - `Unlocking ${key}: ${format_tech(current)}, was ${format_tech(prev)}` - ); -} - - class ResearchSync { constructor(slaveConfig, messageInterface, extras = {}){ this.config = slaveConfig; this.messageInterface = messageInterface; - this.functions = this.loadFunctions(); + this.functions = { + dumpResearch: this.loadFunc("dumpResearch.lua"), + enableResearch: this.loadFunc("enableResearch.lua"), + updateProgress: this.loadFunc("updateProgress.lua") + } this.research = {}; + this.prev_research = {}; setInterval(() => { this.pollResearch(); - setTimeout(this.doSync.bind(this), 2000); + setTimeout(this.request_cluster_data.bind(this), 2000); }, extras.researchSyncPollInterval || 5000); } @@ -32,99 +30,154 @@ class ResearchSync { this.messageInterface(this.functions.dumpResearch); } - doSync() { + request_cluster_data() { const slaves_data_url = `${this.config.masterIP}:${this.config.masterPort}/api/slaves` - needle.get(slaves_data_url, (err, resp, slavesData) => { - if (err) { - this.messageInterface("Unable to post JSON master/api/slaves, master might be unreachable"); - return false; - } - if (resp.statusCode !== 200) { - this.messageInterface("got error when calling slaves", resp.statusCode, resp.body); - return; - } + needle.get(slaves_data_url, this.sync_researches.bind(this)) + } - let needResearch = {}; - for (let slave_data of Object.values(slavesData)) { - if (slave_data.unique === this.config.unique.toString()) - continue; + sync_researches(err, resp, slaves_data) { + if (err) { + this.messageInterface("Unable to post JSON master/api/slaves, master might be unreachable"); + return false; + } + if (resp.statusCode !== 200) { + this.messageInterface("got error when calling slaves", resp.statusCode, resp.body); + return; + } - if (!slave_data.meta || !slave_data.meta.research) - continue; + slaves_data = Object.values(slaves_data) + slaves_data = slaves_data.filter( + slave_data => slave_data.unique !== this.config.unique.toString() + && slave_data.meta && slave_data.meta.research + ) - let researchList = slave_data.meta.research; - for (let [researchName, research] of Object.entries(researchList)) { - if (isNaN(research.researched) || isNaN(research.level)) - continue; + let cluster_techs = this.get_cluster_techs(slaves_data) + this.recount_cluster_research_progress(slaves_data, cluster_techs) - if (needResearch[researchName]) { - if (needResearch[researchName].researched === 0) { - needResearch[researchName].researched = parseInt(research.researched); - } - if (needResearch[researchName].level < parseInt(research.level)) { - needResearch[researchName].level = parseInt(research.level); - } - } - else { - needResearch[researchName] = { - researched: parseInt(researchList[researchName].researched), - level: parseInt(researchList[researchName].level) - }; - } - } - } + let to_research = this.filter_researched_techs(cluster_techs) + let to_update_progress = this.filter_updated_techs(cluster_techs, to_research) - let difference = this.filterResearchDiff(this.research, needResearch); + this.research_technologies(to_research) + this.update_technologies_progress(to_update_progress) - Object.keys(difference).forEach((key) => { - if (!this.research[key]) - return - let command = this.functions.enableResearch; - command = command.replace(/{tech_name}/g, key); - command = command.replace(/{tech_researched}/g, difference[key].researched); - command = command.replace(/{tech_level}/g, difference[key].level); - this.messageInterface(command); - log_tech_unlocking(key, difference[key], this.research[key]) - this.messageInterface( - `Unlocking research: ${key} with research state ${format_tech(difference[key])}` - ); - this.research[key] = difference[key]; - }); - - needle.post(this.config.masterIP + ':' + this.config.masterPort + '/api/editSlaveMeta', { - instanceID: this.config.unique, - password: this.config.clientPassword, - meta: {research: this.research} - }, {headers: {'x-access-token': this.config.masterAuthToken}}, function (err, resp) { - // success? - }); + needle.post(this.config.masterIP + ':' + this.config.masterPort + '/api/editSlaveMeta', { + instanceID: this.config.unique, + password: this.config.clientPassword, + meta: {research: this.research} + }, {headers: {'x-access-token': this.config.masterAuthToken}}, function (err, resp) { + // success? }); } - filterResearchDiff(localResearch, remoteResearch) { - let diff = {}; - for (let key in localResearch) { - if (!remoteResearch[key]) - continue - if (isNaN(remoteResearch[key].researched) || isNaN(remoteResearch[key].level)) - continue + get_cluster_techs(slavesData) { + let researches = {} + for (let slave_data of slavesData) { + let node_researches = slave_data.meta.research + for (let [name, research] of Object.entries(node_researches)) { + if (isNaN(research.researched) || isNaN(research.level)) + continue - if (remoteResearch[key].researched > localResearch[key].researched - || remoteResearch[key].level > localResearch[key].level) { - diff[key] = { - researched: remoteResearch[key].researched, - level: remoteResearch[key].level - }; + if (researches[name]) { + if (researches[name].researched === 0) { + researches[name].researched = parseInt(research.researched) + } + if (researches[name].level < parseInt(research.level)) { + researches[name].level = parseInt(research.level) + } + } else { + researches[name] = { + researched: parseInt(research.researched), + level: parseInt(research.level) + } + } } } - return diff; + return researches } - loadFunctions() { - return { - dumpResearch: this.loadFunc("dumpResearch.lua"), - enableResearch: this.loadFunc("enableResearch.lua"), - }; + recount_cluster_research_progress(slaves_data, cluster_researches) { + for (let research of Object.values(cluster_researches)) + research.progress = research.contribution + + for (let slave_data of slaves_data) + for (let [name, research] of Object.entries(slave_data.meta.research)) + if (!isNaN(cluster_researches[name].progress) && !isNaN(research.contribution)) + cluster_researches[name].progress += research.contribution + + for (let [name, research] of Object.entries(cluster_researches)) { + if (research.progress > 1) { + research.progress = null + research.researched = 1 + if (this.research[name].level >= research.level) + research.level = this.research[name].level + 1 + } + } + } + + filter_researched_techs(cluster_researches) { + let local_researches = this.research + let result = {}; + for (let key in local_researches) { + if (!cluster_researches[key]) + continue + if (isNaN(cluster_researches[key].researched) || isNaN(cluster_researches[key].level)) + continue + + if (cluster_researches[key].researched > local_researches[key].researched + || cluster_researches[key].level > local_researches[key].level) { + result[key] = cluster_researches[key] + } + } + return result; + } + + filter_updated_techs(cluster_techs, to_research) { + let local_techs = this.research + let result = {} + for (let name in local_techs) { + if (name in to_research || !cluster_techs[name]) + continue + if (isNaN(cluster_techs[name].progress)) + continue + if (local_techs[name].progress < cluster_techs[name].progress) + result[name] = cluster_techs[name] + } + return result + } + + research_technologies(to_research) { + for (let [name, tech] of Object.entries(to_research)) { + if (!this.research[name]) + continue + let command = this.functions.enableResearch; + command = command.replace(/{tech_name}/g, key); + command = command.replace(/{tech_researched}/g, tech.researched); + command = command.replace(/{tech_level}/g, tech.level); + this.messageInterface(command); + console.log( + `Unlocking ${name}: ${format_tech(tech)}, was ${format_tech(this.research[name])}` + ); + this.messageInterface( + `Unlocking research: ${name} with research state ${format_tech(tech)}` + ); + this.research[key] = tech; + } + } + + update_technologies_progress(to_update) { + for (let [name, tech] of Object.entries(to_update)) { + if (!this.research[name]) + continue + let command = this.functions.updateProgress + command = command.replace(/{tech_name}/g, name) + command = command.replace(/{last_check_progress}/g, this.research[name].progress) + command = command.replace(/{new_progress}/g, tech.progress) + this.messageInterface(command); + console.log( + `Updating ${name}: progress += ${tech.progress - this.research[name].progress}` + ); + this.research[name].progress = tech.progress + } } loadFunc(path) { @@ -134,11 +187,36 @@ class ResearchSync { return command; } scriptOutput(data) { - let [name, researched, level] = data.split(":") + let [name, researched, level, progress] = data.split(":") researched = +(researched === 'true'); level = parseInt(level); - if (!isNaN(level) && !isNaN(researched)) { - this.research[name] = {researched: researched, level: level}; + if (progress === 'nil') + progress = null + else + progress = parseFloat(progress) + + if (isNaN(level) || isNaN(researched)) + return + this.prev_research[name] = this.research[name] + if (!this.prev_research[name]) { + this.prev_research[name] = { + researched: null, + level: null, + progress: null, + contribution: 0, + } + } + this.research[name] = { + researched, + level, + progress, + contribution: this.prev_research[name].contribution + } + if (this.prev_research[name].progress && this.research[name].progress) { + // this.prev_research[name].progress gets updated to overall cluster progress + // therefore contribution should be own research progress change over sync interval + let contribution = this.research[name].progress - this.prev_research[name].progress + this.research[name].contribution += contribution } } } diff --git a/sharedPlugins/researchSync/index.spec.js b/sharedPlugins/researchSync/index.spec.js index eae51abc..372bf01e 100644 --- a/sharedPlugins/researchSync/index.spec.js +++ b/sharedPlugins/researchSync/index.spec.js @@ -9,7 +9,7 @@ describe("researchSync/index.js", ()=>{ assert.equal(typeof researchSync, "function"); }); describe("class researchSync()", ()=>{ - it(".filterResearchDiff(object1, object2) returns research that needs enabling on the local instance", ()=>{ + it(".filter_researched_techs(object1, object2) returns research that needs enabling on the local instance", ()=>{ let reSync = new researchSync({}, function(){}); let obj1 = { @@ -24,9 +24,9 @@ describe("researchSync/index.js", ()=>{ c:{researched: false, level: 0}, e:{researched: false, level: 50}, }; - assert(typeof reSync.filterResearchDiff == "function"); + assert(typeof reSync.filter_researched_techs == "function"); - let diffResult = reSync.filterResearchDiff(obj1, obj2); + let diffResult = reSync.filter_researched_techs(obj1, obj2); assert(diffResult.a === undefined); diff --git a/sharedPlugins/researchSync/updateProgress.lua b/sharedPlugins/researchSync/updateProgress.lua new file mode 100644 index 00000000..68b7d4ec --- /dev/null +++ b/sharedPlugins/researchSync/updateProgress.lua @@ -0,0 +1,28 @@ + +local function get_tech_progress(tech) + if tech == force.current_research then + return force.research_progress + else + return force.get_saved_technology_progress(tech.name); + end +end +local function set_tech_progress(tech, progress) + if tech == force.current_research then + force.research_progress = progress + else + force.set_saved_technology_progress(tech.name, progress); + end +end + +local force = game.force['player'] +local tech_name = {tech_name} +local tech = force.technologies[tech_name] +local last_check_progress = {last_check_progress} +local new_progress = {new_progress} + +local progress_delta = get_tech_progress(tech) - last_check_progress +new_progress = new_progress + progress_delta +if new_progress > 1 then + new_progress = 1 +end +set_tech_progress(tech, new_progress)