Files
factorio-clusterio/plugins/research_sync/module/sync.lua
T
Hornwitser dcf216ca09 Fix research sync applying progress to wrong level
When the level of a technology changes either by setting level
directly or by setting researched to true, the saved progress of the
research is reset only if the technology is not the current research.

If during the initial synchronisation with the controller an instance
has progressed on a multi level research, it's the current research, and
the controller's level of that research is higher, then the level is set
to the higher level and the game keeps the progress.  This in turn
results in all of the progress made on the previous level being added to
the higher level.

Fix by setting the progress to zero when changing the level or
researched status of a technology that's the active research.
2024-02-06 22:43:04 +01:00

228 lines
5.7 KiB
Lua

local clusterio_api = require("modules/clusterio/api")
local sync = {}
local function get_technology_progress(tech)
if tech == tech.force.current_research then
return tech.force.research_progress
else
return tech.force.get_saved_technology_progress(tech.name)
end
end
local function set_technology_progress(tech, progress)
if tech == tech.force.current_research then
tech.force.research_progress = progress
else
tech.force.set_saved_technology_progress(tech.name, progress)
end
end
sync.events = {}
sync.events[clusterio_api.events.on_server_startup] = function(event)
if not global.research_sync then
global.research_sync = {
technologies = {},
}
end
-- Used when syncing completed technologies from the controller
global.research_sync.ignore_research_finished = false
local force = game.forces["player"]
for _, tech in pairs(force.technologies) do
local progress = get_technology_progress(tech)
global.research_sync.technologies[tech.name] = {
level = tech.level,
researched = tech.researched,
progress = progress,
}
end
end
local function get_contribution(tech)
local progress = get_technology_progress(tech)
if not progress then
return 0, nil
end
local prev_tech = global.research_sync.technologies[tech.name]
if prev_tech.progress and prev_tech.level == tech.level then
return progress - prev_tech.progress, progress
else
return progress, progress
end
end
local function send_contribution(tech)
local contribution, progress = get_contribution(tech)
if contribution ~= 0 then
clusterio_api.send_json("research_sync:contribution", {
name = tech.name,
level = tech.level,
contribution = contribution,
})
global.research_sync.technologies[tech.name].progress = progress
end
end
sync.events[defines.events.on_research_started] = function(event)
local tech = event.last_research
if tech then
send_contribution(tech)
end
end
sync.events[defines.events.on_research_finished] = function(event)
if global.research_sync.ignore_research_finished then
return
end
local tech = event.research
global.research_sync.technologies[tech.name] = {
level = tech.level,
researched = tech.researched,
}
local level = tech.level
if not tech.researched then
level = level - 1
end
clusterio_api.send_json("research_sync:finished", {
name = tech.name,
level = level,
})
end
sync.on_nth_tick = {}
sync.on_nth_tick[79] = function(event)
local tech = game.forces["player"].current_research
if tech then
send_contribution(tech)
end
end
research_sync = {}
function research_sync.dump_technologies()
local force = game.forces["player"]
local techs = {}
for _, tech in pairs(force.technologies) do
table.insert(techs, {
name = tech.name,
level = tech.level,
progress = get_technology_progress(tech),
researched = tech.researched,
})
end
if #techs == 0 then
rcon.print("[]")
else
rcon.print(game.table_to_json(techs))
end
end
function research_sync.sync_technologies(data)
local force = game.forces["player"]
local nameIndex = 1
local levelIndex = 2
local progressIndex = 3
local researchedIndex = 4
global.research_sync.ignore_research_finished = true
for _, tech_data in pairs(game.json_to_table(data)) do
local tech = force.technologies[tech_data[nameIndex]]
if tech and tech.level <= tech_data[levelIndex] then
local new_level = math.min(tech_data[levelIndex], tech.prototype.max_level)
if new_level ~= tech.level then
-- when the level of the current research changes the
-- progress is not automatically reset.
if force.current_research == tech then
force.research_progress = 0
end
tech.level = new_level
end
local progress
if tech_data[researchedIndex] then
if force.current_research == tech then
force.research_progress = 0
end
tech.researched = true
progress = nil
elseif tech_data[progressIndex] then
send_contribution(tech)
progress = tech_data[progressIndex]
set_technology_progress(tech, progress)
else
progress = get_technology_progress(tech)
end
global.research_sync.technologies[tech.name] = {
level = tech.level,
researched = tech.researched,
progress = progress,
}
end
end
global.research_sync.ignore_research_finished = false
end
function research_sync.update_progress(data)
local techs = game.json_to_table(data)
local force = game.forces["player"]
for _, controllerTech in ipairs(techs) do
local tech = force.technologies[controllerTech.name]
if tech and tech.level == controllerTech.level then
send_contribution(tech)
set_technology_progress(tech, controllerTech.progress)
global.research_sync.technologies[tech.name] = {
level = tech.level,
progress = controllerTech.progress
}
end
end
end
function research_sync.research_technology(name, level)
local force = game.forces["player"]
local tech = force.technologies[name]
if not tech or tech.level > level then
return
end
if level > tech.prototype.max_level then
level = tech.prototype.max_level
end
global.research_sync.ignore_research_finished = true
if tech == force.current_research and tech.level == level then
force.research_progress = 1
elseif tech.level < level or tech.level == level and not tech.researched then
tech.level = level
tech.researched = true
if tech.name:find("-%d+$") then
game.print {"", "Researched ", {"technology-name." .. tech.name:gsub("-%d+$", "")}, " ", level}
else
game.print {"", "Researched ", {"technology-name." .. tech.name}}
end
game.play_sound { path = "utility/research_completed" }
end
global.research_sync.ignore_research_finished = false
global.research_sync.technologies[tech.name] = {
level = tech.level,
researched = tech.researched,
}
end
return sync