Make researchSync work for any research on any node

This commit is contained in:
TechnoStrife committed 2019-07-15 00:46:21 +03:00
1 parent fa4c10dce2
commit 98c6795f8f
4 files changed
+208 -94

No files matched your search

+9 -1
View File
@@ -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);
+168 -90
View File
@@ -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
}
}
}
+3 -3
View File
@@ -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);
@@ -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)