Addressing Desync
-
- Burner Inserter
- Posts: 6
- Joined: Thu Jan 24, 2019 2:38 am
- Contact:
Addressing Desync
I'm new to modding but familiar with coding practices. I have recently enjoyed a mod enough to give it an update. The problem my friends and I had when playing is the desync issues when trying to reload a save from the mod. The previous developer hasn't touched it in two years but left a note that they had to fix the issue on saving and during map generation.
I've tried building from the ground up and going with the main advice about desync issues: use global variables in the manner for factorio (global.variable_name). but somehow I've run into more desync issues than trying to update the old mod.
I am looking for any knowledge on how to approach desync issues since, so far, I have read there is not a great way to determine where they originate and there isn't a good way to error log them without just perusing log files for awhile.
Thanks in advance.
I've tried building from the ground up and going with the main advice about desync issues: use global variables in the manner for factorio (global.variable_name). but somehow I've run into more desync issues than trying to update the old mod.
I am looking for any knowledge on how to approach desync issues since, so far, I have read there is not a great way to determine where they originate and there isn't a good way to error log them without just perusing log files for awhile.
Thanks in advance.
Re: Addressing Desync
Search the code for any function named on_load. Delete it.
Search the code for any variable defined outside a function. Delete it and move it to global.variable inside an event function.
Search the code for any variable defined outside a function. Delete it and move it to global.variable inside an event function.
-
- Burner Inserter
- Posts: 6
- Joined: Thu Jan 24, 2019 2:38 am
- Contact:
Re: Addressing Desync
I have taken the few variables left outside event functions and defined them in functions. I also took the time reorganize the global variables. I was already aware of on_load and had removed it previously.
Having the recommended desync prevention has no effect on when other players are desync'd. I can narrow down what action causes the desync being completing configuration that "Player 1" does to setup team information, which at this point just updates global variables.
Are there further recommendations to track down why exactly some actions descync players?
Edit: The desync seems almost 'tick' related to on_tick. The outdated mod included a tick_helper I assume to counter this.
Having the recommended desync prevention has no effect on when other players are desync'd. I can narrow down what action causes the desync being completing configuration that "Player 1" does to setup team information, which at this point just updates global variables.
Are there further recommendations to track down why exactly some actions descync players?
Edit: The desync seems almost 'tick' related to on_tick. The outdated mod included a tick_helper I assume to counter this.
Re: Addressing Desync
The code you suspect of causing a desync would be useful to help figure out what is wrong with it.
Does the desync also happen on a fresh game or just when changing from the old mod to your new one?TheOverwatcher wrote: ↑Thu Jan 24, 2019 2:45 amThe problem my friends and I had when playing is the desync issues when trying to reload a save from the mod.
-
- Burner Inserter
- Posts: 6
- Joined: Thu Jan 24, 2019 2:38 am
- Contact:
Re: Addressing Desync
Any new game causes the issue. There are two scenarios of desync:
The following is the code from the ticker helper, but is called from control.lua and some other helper lua files.
Here is the control.lua
For reference, the gui that configuration setup is through is laid out in the following configuration_gui.lua
- 1. When using the old mod and loading a save. At this point I don't care about this since I can't get other players not to desync on 2.
2. After building from the ground up, finishing the intial configuration, and "starting the game" where ticks are used.
The following is the code from the ticker helper, but is called from control.lua and some other helper lua files.
Code: Select all
function register_tick_helper(f, name)
global._tick_helper[name] = f;
end
function destroy_tick_helper(name)
global._tick_helper[name] = nil;
end
function tick_all_helper(tick)
for k,f in pairs(global._tick_helper) do
pcall(f,tick);
end
end
function tick_all_helper_if_valid(tick)
for k,data in pairs(global._tick_helper_v) do
if data.next_tick == tick then
if data.running == false then
global._tick_helper_v[k].running = true;
local status, r = pcall(data.if_valid, tick);
if status and r then
pcall(data.tick_helper,tick);
global._tick_helper_v[k].running = false;
destroy_tick_helper_if_valid(k);
else
global._tick_helper_v[k].next_tick = tick + global.TICK_INTERVAL--data.tick_interval
global._tick_helper_v[k].running = false;
end
end
end
end
end
function register_tick_helper_if_valid(name, tick_helper, tick_interval, if_valid)
global._tick_helper_v[name] = {
tick_helper=tick_helper,
name = name,
if_valid = if_valid,
--tick_interval = global.TICK_INTERVAL,
next_tick = game.tick + global.TICK_INTERVAL,
running = false
}
end
function destroy_tick_helper_if_valid(name)
global._tick_helper_v[name] = nil;
end
Code: Select all
require("constants")
require("utility.event")
require("utility.map_helpers")
require("utility.math")
require("utility.position")
require("utility.table")
require("utility.tick_helper")
require("utility.utilities")
require("utility.configuration_gui")
function areTeamsEnabled()
return global.TEAMS_ENABLED or false;
end
function setTeamsEnabled()
global.TEAMS_ENABLED = true;
end
function areTeamsEnabledStartup()
return global.TEAMS_ENABLED_STARTUP or false;
end
function setTeamsEnabledStartup()
global.TEAMS_ENABLED_STARTUP = true;
end
function isConfigWritten()
return global.CONFIG_WRITTEN or false;
end
function setConfigWritten()
if isConfigWritten() == false then
global.CONFIG_WRITTEN_TIME = game.tick
end
global.CONFIG_WRITTEN = true;
end
function make_forces()
global.LAST_POINT = nil
global.USED_POINTS = {}
global.s = game.surfaces["nauvis"]
table.each(global.forcesData, function(data, k)
if data.cords == nil then
global.RANDOM_POINT = MM_get_random_point(global.USED_POINTS, global.LAST_POINT);
global.LAST_POINT = global.RANDOM_POINT;
global.RANDOM_POINT.x = Rnd(220,1060)
global.RANDOM_POINT.y = Rnd(220,1060)
global.forcesData[k].team_x = global.RANDOM_POINT.x
global.forcesData[k].team_y = global.RANDOM_POINT.y
global.forcesData[k].team_position = { global.forcesData[k].team_x, global.forcesData[k].team_y }
global.forcesData[k].cords = { x = global.forcesData[k].team_x, y = global.forcesData[k].team_y }
global.forcesData[k].team_area = { { global.forcesData[k].team_x - global.distance, global.forcesData[k].team_y - global.distance }, { global.forcesData[k].team_x + global.distance, global.forcesData[k].team_y + global.distance } }
global.LAST_POINT = global.forcesData[k].cords
table.insert(global.USED_POINTS, global.LAST_POINT)
-- logTable(global.forcesData[k],k);
end
MM_create_force(data);
end);
end
function Rnd(min,max,adseed)
min = min or 1
max = max or 1
adseed = adseed or game.tick
global.adseed = global.adseed or 42
global.adseed = global.adseed + adseed
global.adseed = global.adseed < 0 and 0 - global.adseed or global.adseed
global.adseed = global.adseed >= 2^32-1 and 1 or global.adseed
global.seed = game.tick + math.floor(tonumber(tostring({}):sub(8,-4))) + adseed
global.seed = global.seed < 0 and 0 - global.seed or global.seed
global.seed = global.seed >= 2^32-1 and game.tick or global.seed
if not global.generator then
global.generator = game.create_random_generator(global.seed)
else
global.generator.re_seed(global.seed)
end
return math.min(max, math.max(min, math.floor(global.generator(min, math.max(min, max + global.adseed)) % max) ) )
end
function set_spawns()
global.s = game.surfaces['nauvis'];
game.daytime = 0.9
table.each(global.forcesData, function(data)
MM_set_spawns(data);
end)
end
function set_starting_areas()
global.s = game.surfaces['nauvis'];
table.each(global.forcesData, function(data)
MM_set_starting_area(data);
end)
end
function make_team_option(player)
if global.player.gui.left.choose_team == nil then
global.frame = global.player.gui.left.add { name = "choose_team", type = "frame", direction = "vertical", caption = { "resources.team-choose" } }
table.each(global.forcesData, function(data)
global.frame.add { type = "button", caption = { 'resources.team-join', data.title }, name = 'choose_team_' .. data.name }.style.font_color = data.color
end)
global.frame.add { type = "button", caption = { "resources.team-auto-assign"}, name = "autoAssign" }
global.frame.add { type = "button", caption = { "resources.team-check-number" }, name = "team_number_check" }.style.font_color = { r = 0.9, g = 0.9, b = 0.9 }
end
end
function make_lobby()
game.create_surface("Lobby", { width = 96, height = 32, starting_area = "big", water = "none" })
end
function on_init(event)
make_lobby()
-- global information modified from initial config
if global.forcesData == nil then
global.forcesData = {}
end
if global.points == nil then
global.points = {
startingAreaRadius = 50, -- in this radius every tree will be destroyed
start = {
-- defines start point of map
x = 0,--math.random(220, 1060),
y = 0--math.random(220, 1060)
}, -- defines distance between spawn points for teams
distance = {
min = 1200,
max = 1800,
},
numberOfTrysBeforeError = 40 -- this is just a helper value (if we try to locate a non colliding point, we try it max XX times before we abort)
}
end
if global.distance == nil then
global.distance = 60 * 3
end
if global.big_distance == nil then
global.big_distance = 40 * 3 * 3
end
if global.researchMessage == nil then
global.researchMessage = {
enabled = true
}
end
if global.attackMessage == nil then
global.attackMessage = {
enabled = true,
interval = 5*MINUTES
}
end
if global.enableTeams == nil then
global.enableTeams = {
after = 30 * SECONDS, -- teams are eneabled after XX Seconds
messageInterval = 10 * SECONDS -- message interval /(when are the teams unlocked)
}
end
if global.teamBalance == nil then
global.teamBalance = {
enabled = true, -- wether team balance should be enabled or not
}
end
if global.teamMessageGui == nil then
global.teamMessageGui = {
enabled = true
}
end
if global.allianceGui == nil then
global.allianceGui = {
enabled = true,
changeAbleTick = 5 * MINUTES -- alliances could only be changed every XXX ticks
}
end
global._tick_helper = {};
global._tick_helper_v = {};
end
function on_player_created(event)
--Get the player that just joined
global.player = game.players[event.player_index]
--Take them to the lobby
global.player.teleport({ 0, 8 }, game.surfaces["Lobby"])
PrintToAllPlayers("A challenger has approached.")
--If the host player and configuration was not set.
if global.player.index == 1 and not isConfigWritten() then
PrintToAllPlayers('Creating configuration gui');
ConfigurationGui:createConfigurationGui(global.player);
end
--Print messages to new arrivals
if areTeamsEnabled() then
PrintToAllPlayers({"resources.please-select-team-msg"})
make_team_option(global.player)
else
PrintToAllPlayers({"resources.teams-have-not-been-set-msg"})
end
global.player.get_inventory(defines.inventory.player_ammo).clear();
global.player.get_inventory(defines.inventory.chest).clear();
global.player.get_inventory(defines.inventory.player_guns).clear();
global.player.get_inventory(defines.inventory.player_main).clear();
global.player.get_inventory(defines.inventory.player_quickbar).clear();
end
script.on_init(on_init);
script.on_event(defines.events.on_player_created, on_player_created);
function after_lobby_tick(event)
tick_all_helper(event.tick);
tick_all_helper_if_valid(event.tick);
end
function triggerTeamsEnabling()
global.TRIGGER_TEAMS_SECONDS = 10;
global.TICK_INTERVAL = global.TRIGGER_TEAMS_SECONDS * SECONDS;
PrintToAllPlayers({ "resources.teams-enable-wait-to-be-charted" })
-- PrintToAllPlayers('Wait for team areas to be charted');
global.checked_teams = {};
global.if_valid = function(tick)
PrintToAllPlayers("checking if valid")
for _, data in pairs(global.forcesData) do
PrintToAllPlayers(checked_teams[data.name])
if checked_teams[data.name] == nil then
PrintToAllPlayers("Checked teams is nil")
if is_area_charted(round_area_to_chunk_save(SquareArea(data.cords, global.big_distance)), global.s) == false then
PrintToAllPlayers("is area charted check")
--PrintToAllPlayers({ 'resources.teams-enable-not-charted-yet', data.title, seconds })
return false;
end
PrintToAllPlayers("set true for team")
--PrintToAllPlayers({ 'resources.team-area-charted', data.title })
checked_teams[data.name] = true;
end
end
return true;
end
global.tick_helper = function(tick)
table.each(global.forcesData, function(data)
MM_set_spawns(data);
MM_set_starting_area(data);
end)
setTeamsEnabled();
table.each(game.players, function(p)
make_team_option(p);
end)
end
register_tick_helper_if_valid('CREATE_TEAMS', global.tick_helper, global.tick_interval, global.if_valid);
end
function putPlayerInTeam(player, forceData)
global.s = game.surfaces['nauvis'];
global.player.teleport(game.forces[forceData.cName].get_spawn_position(global.s), global.s)
global.player.color = forceData.color
global.player.force = game.forces[forceData.cName]
player.gui.left.choose_team.destroy()
global.player.insert { name = "iron-plate", count = 8 }
global.player.insert { name = "pistol", count = 1 }
global.player.insert { name = "firearm-magazine", count = 10 }
global.player.insert { name = "burner-mining-drill", count = 1 }
global.player.insert { name = "stone-furnace", count = 1 }
Alliance:make_alliance_overlay_button(player);
TeamChat:make_team_chat_button(player);
PrintToAllPlayers({ 'teams.player-msg-team-join', global.player.name, forceData.title })
end
function couldJoinIntoForce(forceName)
if global.teamBalance.enabled == false then
return true;
end
global.check = {}
global.lastValue = 0;
global.onlyOne = false;
table.each(global.forcesData, function(data)
global.c = 0;
table.each(game.players, function(p)
if data.cName == global.player.force.name then c = c + 1 end
end)
check[data.cName] = global.c;
if global.lastValue == global.c then -- check if all teams have the same amount of players
global.onlyOne = true;
else
global.onlyOne = false;
end
global.lastValue = global.c
end)
if global.onlyOne == true then -- if all teams have the same amount of players, then it is possible to join this team
return true;
end
for k,v in spairs(check) do
return check[forceName] < v -- only join, if wanted force has fewer amount of players as the largest team
end
return true;
end
function lobby_tick(event)
tick_all_helper(event.tick);
tick_all_helper_if_valid(event.tick);
if game.tick >= global.CONFIG_WRITTEN_TIME + global.enableTeams.after then
-- fix if game is saved and reload during generation
PrintToAllPlayers("Are teams enabled:")
PrintToAllPlayers(areTeamsEnabledStartup())
--teamsEnablingStarted = areTeamsEnabledStartup();
if areTeamsEnabledStartup() == false then
--teamsEnablingStarted = true;
setTeamsEnabledStartup();
triggerTeamsEnabling();
end
elseif game.tick <= global.CONFIG_WRITTEN_TIME + global.enableTeams.after and game.tick % global.enableTeams.messageInterval == 0 then
global.enableTick = (global.CONFIG_WRITTEN_TIME + global.enableTeams.after) - game.tick;
global.seconds = Math.round(global.enableTick / SECONDS);
PrintToAllPlayers({ 'resources.teams-enable-in', global.seconds })
end
if (areTeamsEnabled()) then
script.on_event(defines.events.on_tick, nil)
script.on_event(defines.events.on_tick, after_lobby_tick)
end
end
script.on_event(defines.events.on_tick,
function(event)
if isConfigWritten() then
--PrintToAllPlayers("on_tick event - config written")
script.on_event(defines.events.on_tick, lobby_tick);
end
--fire armor
if event.tick % 60 == 0 then --common trick to reduce how often this runs, we don't want it running every tick, just 1/second
for index,player in pairs(game.connected_players) do --loop through all online players on the server
--if they're wearing our armor
if global.player.character and global.player.get_inventory(defines.inventory.player_armor).get_item_count("fire-armor") >= 1 then
--create the fire where they're standing
global.player.surface.create_entity{name="fire-flame", position=global.player.position, force="neutral"}
end
end
end
end
)
--Handling the gui clicks
script.on_event(defines.events.on_gui_click,
function(event)
global.s = game.surfaces.nauvis;
global.element = event.element
if global.element.valid ~= true then
return;
end
global.eventName = global.element.name;
global.player = game.players[event.player_index];
--Frame related
if global.eventName == 'next_step' then
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].saveStep, global.player);
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].destroyStep, global.player);
ConfigurationGui.currentStep = ConfigurationGui.steps[ConfigurationGui.currentStep].nextStep;
global.g = ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].createStep, global.player);
ConfigurationGui:createNextAndPrev(global.g);
elseif global.eventName == 'prev_step' then
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].saveStep, global.player);
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].destroyStep, global.player);
ConfigurationGui.currentStep = ConfigurationGui.steps[ConfigurationGui.currentStep].prevStep;
global.g = ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].createStep, global.player);
ConfigurationGui:createNextAndPrev(global.g);
elseif global.eventName == 'start_game' then
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].saveStep, global.player);
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].destroyStep, global.player);
PrintToAllPlayers({ "lobby.lobby-msg-config-finished", game.players[1].name })
make_forces()
setConfigWritten();
elseif global.eventName == 'force_cancel' then
if global.player.gui.center.create_force ~= nil and global.player.gui.center.create_force.valid then
global.player.gui.center.create_force.destroy();
end
ConfigurationGui:createNextAndPrev(ConfigurationGui.steps.teams.createFrame(global.player));
--Force related
elseif global.eventName == 'force_save' then
if global.player.gui.center.create_force ~= nil and global.player.gui.center.create_force.valid then
if global.player.gui.center.create_force.caption ~= nil then
global.forcesData[global.player.gui.center.create_force.caption] = nil;
end
global.forceData = ConfigurationGui.steps.teams.getForceData(global.player.gui.center.create_force);
if global.forceData.cName ~= '' then
global.forcesData[global.forceData.cName] = global.forceData;
global.player.gui.center.create_force.destroy();
end
end
ConfigurationGui:createNextAndPrev(ConfigurationGui.steps.teams.createFrame(global.player));
elseif global.eventName == 'force_remove' then
global.parent = global.element.parent;
table.each(global.forcesData, function(forceData, k)
if global.parent.name == 'force_frame_' .. forceData.name then
global.forcesData[k] = nil;
end
end)
ConfigurationGui:createNextAndPrev(ConfigurationGui.steps.teams.createFrame(global.player));
elseif string.match(global.eventName,'force_edit_(.*)') ~= nil then
table.each(global.forcesData, function(forceData)
if global.element.valid and global.element.name == 'force_edit_' .. forceData.name then
if global.player.gui.center.teams_gui ~= nil then
global.player.gui.center.teams_gui.destroy();
end
ConfigurationGui.steps.teams.createForceGuiWithData(global.player, forceData);
return;
end
end)
elseif global.eventName == 'force_new' then
if global.player.gui.center.teams_gui ~= nil then
global.player.gui.center.teams_gui.destroy();
end
ConfigurationGui.steps.teams.createForceGui(p);
--team realated
elseif global.eventName == 'team_number_check' then
table.each(global.forcesData, function(data)
global.c = 0;
table.each(game.players, function(p)
if data.cName == global.player.force.name then global.c = global.c + 1 end
end)
global.player.print({ 'resources.player-msg-team-number', data.title, global.c })
end)
elseif global.eventName == 'autoAssign' then
global.check = {}
table.each(global.forcesData, function(data)
global.c = 0;
table.each(game.players, function(p)
if data.cName == global.p.force.name then global.c = global.c + 1 end
end)
global.check[data.cName] = global.c;
end)
for k,v in spairs(global.check, function (t,a,b) return t[a] < t[b] end) do
putPlayerInTeam(global.player, global.forcesData[k]);
break
end
elseif string.match(global.eventName, 'choose_team_.*') ~= nil then
table.each(global.forcesData, function(data)
if global.eventName == 'choose_team_' .. data.name then
if couldJoinIntoForce(data.cName) then
putPlayerInTeam(global.player, data);
else
global.player.print( { 'resources.player-msg-could-not-join', data.title } )
end
end
end)
end
end
) --end event handler for gui click
-- Normal Events for game changes (launching rocket, dieing)
script.on_event(defines.events.on_rocket_launched, function(event)
local force = event.rocket.force
if event.rocket.get_item_count("satellite") > 0 then
if global.satellite_sent == nil then
global.satellite_sent = {}
end
if global.satellite_sent[force.name] == nil then
game.set_game_state { game_finished = true, player_won = true, can_continue = true }
global.satellite_sent[force.name] = 1
else
global.satellite_sent[force.name] = global.satellite_sent[force.name] + 1
end
for index, player in pairs(force.players) do
if global.player.gui.left.rocket_score == nil then
local frame = global.player.gui.left.add { name = "rocket_score", type = "frame", direction = "horizontal", caption = { "score" } }
frame.add { name = "rocket_count_label", type = "label", caption = { "", { "rockets-sent" }, "" } }
frame.add { name = "rocket_count", type = "label", caption = "1" }
else
global.player.gui.left.rocket_score.rocket_count.caption = tostring(global.satellite_sent[force.name])
end
end
else
if (#game.players <= 1) then
game.show_message_dialog { text = { "gui-rocket-silo.rocket-launched-without-satellite" } }
else
for index, player in pairs(force.players) do
global.player.print({ "gui-rocket-silo.rocket-launched-without-satellite" })
end
end
end
end)
script.on_event(defines.events.on_research_started, function(event)
if global.researchMessage.enabled then
local force = event.research.force
PrintToAllPlayers({ 'teams.team-research-start', global.forcesData[force.name].title, { 'research-name' .. event.research.name } })
-- ResearchNotification.log('Team ' .. force.name .. ' has starting research ' .. event.research.name, force.name);
end
end)
script.on_event(defines.events.on_research_finished, function(event)
if global.researchMessage.enabled then
local force = event.research.force
PrintToAllPlayers({ 'teams.team-research-end', global.forcesData[force.name].title, { 'research-name' .. event.research.name } })
end
end)
script.on_event(defines.events.on_entity_died, function(event)
if global.attackMessage.enabled then
global.entity = event.entity;
global.force = event.force;
if global.force ~= nil and global.entity.force.name ~= 'neutral' then
if global.entity.force.name == 'enemy' then
if global.entity.name ~= "spitter-spawner"
and global.entity.name ~= "biter-spawner"
and global.entity.name ~= "small-worm-turret"
and global.entity.name ~= "medium-worm-turret"
and global.entity.name ~= "big-worm-turret"
then
return
end
end
if global.entity.force ~= nil and global.entity.force ~= global.force then
global.attacked = global.entity.force.name;
global.attackedFrom = global.force.name;
if global.attacked == 'enemy' then
global.attacked = 'Aliens'
end
if global.attackedFrom == 'enemy' then
global.attackedFrom = 'Aliens';
end
PrintToAllPlayers({ 'teams.team-attacked-by-team', global.attacked, global.attackedFrom })
end
end
end
end)
Code: Select all
ConfigurationGui = {}
ConfigurationGui.steps = {
teams = {
prevStep = nil,
nextStep = 'enable',
caption = { 'resources-gui.forces-gui-caption' },
createFrame = function(player)
--if it already exists, close it
if player.gui.center.teams_gui ~= nil then
player.gui.center.teams_gui.destroy();
end
--create the frame
global.frame = ConfigurationGui:createFrame(player.gui.center, 'teams_gui', { 'resources-gui.create-gui-caption' });
PrintToAllPlayers("Debug for table each.")
table.each(global.forcesData, function(forceData)
global.forceFrame = global.frame.add {
name = 'force_frame_' .. forceData.name,
type = 'flow',
direction = 'horizontal'
}
global.forceFrame.add {
type = 'label',
--name = 'name', @2.1.1
caption = forceData.title
}.style.font_color = forceData.color
global.forceFrame.add {
type = 'button',
name = 'force_edit_' .. forceData.name,
caption = { 'resources-gui.force-edit-caption' }
}
if game.forces[forceData.name] == nil then
global.forceFrame.add {
type = 'button',
name = 'force_remove',
caption = { 'resources-gui.force-remove-caption' }
}
end
end)
global.frame.add {
type = 'button',
name = 'force_new',
caption = { 'resources-gui.force-new-caption' }
}
return global.frame;
end,
createForceGuiWithData = function(player, forceData)
if global.player.gui.center.create_force ~= nil then
global.player.gui.center.create_force.destroy();
end
global.frame = ConfigurationGui:createFrame(global.player.gui.center, 'create_force', { 'resources-gui.create-gui-caption' });
if forceData.cName ~= '' then
global.frame.caption = forceData.cName;
end
for k, v in pairs({
'name',
'title',
'cName'
}) do
global.flow = global.frame.add {
type = 'flow',
name = "force_" .. v,
direction = 'vertical'
}
global.flow.add {
type = "label",
caption = { 'resources-gui.force-' .. v .. '-caption' }
}
global.flow.add {
name = "textfield",
type = "textfield",
text = forceData[v],
}
end
global.color = global.frame.add {
type = 'frame',
direction = 'vertical',
name = 'color',
caption = { 'resources-gui.force-color-caption' }
}
global.forceColor = ConfigurationGui:colorToRgb(forceData.color)
for k, v in pairs(global.forceColor) do
global.flow = global.color.add {
type = 'flow',
direction = 'horizontal',
name = k
}
global.flow.add {
type = "label",
caption = { 'resources-gui.force-color-' .. k .. '-caption' }
}
global.flow.add {
name = "textfield",
text = v,
type = "textfield",
}
end
global.frame.add {
type = 'button',
name = 'force_cancel',
caption = { 'resources-gui.force-cancel-caption' }
}
global.frame.add {
type = 'button',
name = 'force_save',
caption = { 'resources-gui.force-save-caption' }
}
end,
createForceGui = function(player)
local forceData = {
name = "",
title = "",
cName = '',
color = { r = 1, g = 1, b = 1, a = 1 }
}
ConfigurationGui.steps.teams.createForceGuiWithData(player, forceData);
end,
getForceData = function(frame)
return {
name = frame.force_name.textfield.text,
title = frame.force_title.textfield.text,
cName = frame.force_cName.textfield.text,
color = ConfigurationGui:rgbToColor({
r = frame.color.r.textfield.text,
g = frame.color.g.textfield.text,
b = frame.color.b.textfield.text,
a = frame.color.a.textfield.text
})
}
end,
createStep = function(player)
return ConfigurationGui.steps.teams.createFrame(player);
end,
saveStep = function(player) end,
destroyStep = function(player)
if player.gui.center.teams_gui ~= nil then
player.gui.center.teams_gui.destroy();
end
end
},
enable = {
prevStep = 'teams',
nextStep = 'points',
caption = { 'enable-gui.caption' },
createStep = function(player)
global.frame = ConfigurationGui:createFrame(player.gui.center, 'enable_gui', { 'enable-gui.caption' });
--table.each({
-- "attackMessage",
-- "researchMessage",
-- "teamMessageGui",
-- "allianceGui",
-- "teamBalance"
-- },
--function(name)
ConfigurationGui:createCheckboxFlow(global.frame, "attackMessage", { 'enable-gui.label-' .. "attackMessage" }, global.attackMessage.enabled)
ConfigurationGui:createCheckboxFlow(global.frame, "researchMessage", { 'enable-gui.label-' .. "researchMessage" }, global.researchMessage.enabled)
ConfigurationGui:createCheckboxFlow(global.frame, "teamMessageGui", { 'enable-gui.label-' .. "teamMessageGui" }, global.teamMessageGui.enabled)
ConfigurationGui:createCheckboxFlow(global.frame, "allianceGui", { 'enable-gui.label-' .. "allianceGui" }, global.allianceGui.enabled)
ConfigurationGui:createCheckboxFlow(global.frame, "teamBalance", { 'enable-gui.label-' .. "teamBalance" }, global.teamBalance.enabled)
--end
--)
return global.frame
end,
saveStep = function(player)
--table.each({
-- "attackMessage",
-- "researchMessage",
-- "teamMessageGui",
-- "allianceGui",
-- "teamBalance"
--},
--function(name)
global.attackMessage.enabled = player.gui.center.enable_gui["attackMessage"].checkbox.state
global.researchMessage.enabled = player.gui.center.enable_gui["researchMessage"].checkbox.state
global.teamMessageGui.enabled = player.gui.center.enable_gui["teamMessageGui"].checkbox.state
global.allianceGui.enabled = player.gui.center.enable_gui["allianceGui"].checkbox.state
global.teamBalance.enabled = player.gui.center.enable_gui["teamBalance"].checkbox.state
-- end
-- )
end,
destroyStep = function(player)
if player.gui.center.enable_gui ~= nil then
player.gui.center.enable_gui.destroy();
end
end
},
points = {
prevStep = 'enable',
nextStep = nil,
caption = { 'point-gui.caption' },
createStep = function(player)
global.frame = ConfigurationGui:createFrame(player.gui.center, 'point_gui', { 'point-gui.caption' });
ConfigurationGui:createTextFieldFlow(global.frame, 'startingAreaRadius', { 'point-gui.label-startingAreaRadius' }, global.points.startingAreaRadius);
ConfigurationGui:createTextFieldFlow(global.frame, 'pointsMin', { 'point-gui.label-distance-min' }, global.points.distance.min);
ConfigurationGui:createTextFieldFlow(global.frame, 'pointsMax', { 'point-gui.label-distance-max' }, global.points.distance.max);
ConfigurationGui:createTextFieldFlow(global.frame, 'd', { 'point-gui.label-distance' }, global.distance);
ConfigurationGui:createTextFieldFlow(global.frame, 'bd', { 'point-gui.label-big-distance' }, global.big_distance);
return global.frame;
end,
saveStep = function(player)
global.gui = player.gui.center.point_gui;
global.distance = tonumber(global.gui.d.textfield.text);
global.big_distance = tonumber(global.gui.bd.textfield.text);
global.points.startingAreaRadius = tonumber(global.gui.startingAreaRadius.textfield.text);
global.points.distance.min = tonumber(global.gui.pointsMin.textfield.text);
global.points.distance.max = tonumber(global.gui.pointsMax.textfield.text);
end,
destroyStep = function(player)
if player.gui.center.point_gui ~= nil then
player.gui.center.point_gui.destroy();
end
end
}
}
function ConfigurationGui:createNextAndPrev(gui)
global.f = gui.add {
type = 'flow',
direction = 'horizontal'
}
global.s = ConfigurationGui.steps[ConfigurationGui.currentStep];
if global.s.prevStep ~= nil then
global.f.add {
type = 'button',
name = 'prev_step',
caption = { '', '< ', ConfigurationGui.steps[global.s.prevStep].caption }
}
end
if global.s.nextStep == nil then
if global.forcesData ~= nil and table.length(global.forcesData) > 0 then
global.f.add {
type = 'button',
name = 'start_game',
caption = { 'config-gui.start' }
}
else
global.f.add {
type = 'label',
caption = { 'config-gui.min-one-team' }
}
end
else
global.f.add {
type = 'button',
name = 'next_step',
caption = { '', ConfigurationGui.steps[global.s.nextStep].caption, ' >' }
}
end
end
ConfigurationGui.currentStep = 'teams';
function ConfigurationGui:createConfigurationGui(player)
-- init first step
global.g = ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].createStep, player);
ConfigurationGui:createNextAndPrev(global.g);
end
function ConfigurationGui:try(f, ...)
global.status, r = pcall(f, ...);
if not global.status then
PrintToAllPlayers(r);
end
return r;
end
function ConfigurationGui:createFrame(parent, name, caption)
return parent.add {
type = 'frame',
name = name,
direction = 'vertical',
caption = caption
}
end
function ConfigurationGui:createTextFieldFlow(gui, name, caption, value)
global.flow = gui.add {
type = 'flow',
direction = 'horizontal',
name = name
}
global.flow.add {
type = "label",
caption = caption
}
global.flow.add {
name = "textfield",
type = "textfield",
text = value,
}
end
function ConfigurationGui:createCheckboxFlow(gui, name, caption, value)
global.flow = gui.add {
type = 'flow',
direction = 'horizontal',
name = name
}
global.flow.add {
type = "label",
caption = caption
}
global.flow.add {
name = "checkbox",
type = "checkbox",
state = value,
}
end
function ConfigurationGui:colorToRgb(color)
return {
r = color.r * 255,
g = color.g * 255,
b = color.b * 255,
a = color.a
}
end
function ConfigurationGui:rgbToColor(rgb)
return {
r = rgb.r / 255,
g = rgb.g / 255,
b = rgb.b / 255,
a = rgb.a
}
end
Re: Addressing Desync
You call
... in 4 different places, without sufficient desync protection. (This is one of the three specific reasons where on_load is actually needed). I recommend reducing it to 1 call.
Code: Select all
script.on_event(defines.events.on_tick
-
- Burner Inserter
- Posts: 6
- Joined: Thu Jan 24, 2019 2:38 am
- Contact:
Re: Addressing Desync
Ended up replacing the calls down to just one. The desync still happens when the on_tick event occurs.
You recommended reducing to one call but do you recommend anything or see any other issues with the way it's currently laid out? Basically all I did was move the extra on_tick's into one.
On_load still seems to be during the save-load cycle and I haven't gotten there yet.
Code: Select all
require("constants")
require("utility.event")
require("utility.map_helpers")
require("utility.math")
require("utility.position")
require("utility.table")
require("utility.tick_helper")
require("utility.utilities")
require("utility.configuration_gui")
function areTeamsEnabled()
return global.TEAMS_ENABLED or false;
end
function setTeamsEnabled()
global.TEAMS_ENABLED = true;
end
function areTeamsEnabledStartup()
return global.TEAMS_ENABLED_STARTUP or false;
end
function setTeamsEnabledStartup()
global.TEAMS_ENABLED_STARTUP = true;
end
function isConfigWritten()
return global.CONFIG_WRITTEN or false;
end
function setConfigWritten()
if isConfigWritten() == false then
global.CONFIG_WRITTEN_TIME = game.tick
end
global.CONFIG_WRITTEN = true;
end
function make_forces()
global.LAST_POINT = nil
global.USED_POINTS = {}
global.s = game.surfaces["nauvis"]
table.each(global.forcesData, function(data, k)
if data.cords == nil then
global.RANDOM_POINT = MM_get_random_point(global.USED_POINTS, global.LAST_POINT);
global.LAST_POINT = global.RANDOM_POINT;
global.RANDOM_POINT.x = Rnd(220,1060)
global.RANDOM_POINT.y = Rnd(220,1060)
global.forcesData[k].team_x = global.RANDOM_POINT.x
global.forcesData[k].team_y = global.RANDOM_POINT.y
global.forcesData[k].team_position = { global.forcesData[k].team_x, global.forcesData[k].team_y }
global.forcesData[k].cords = { x = global.forcesData[k].team_x, y = global.forcesData[k].team_y }
global.forcesData[k].team_area = { { global.forcesData[k].team_x - global.distance, global.forcesData[k].team_y - global.distance }, { global.forcesData[k].team_x + global.distance, global.forcesData[k].team_y + global.distance } }
global.LAST_POINT = global.forcesData[k].cords
table.insert(global.USED_POINTS, global.LAST_POINT)
-- logTable(global.forcesData[k],k);
end
MM_create_force(data);
end);
end
function Rnd(min,max,adseed)
min = min or 1
max = max or 1
adseed = adseed or game.tick
global.adseed = global.adseed or 42
global.adseed = global.adseed + adseed
global.adseed = global.adseed < 0 and 0 - global.adseed or global.adseed
global.adseed = global.adseed >= 2^32-1 and 1 or global.adseed
global.seed = game.tick + math.floor(tonumber(tostring({}):sub(8,-4))) + adseed
global.seed = global.seed < 0 and 0 - global.seed or global.seed
global.seed = global.seed >= 2^32-1 and game.tick or global.seed
if not global.generator then
global.generator = game.create_random_generator(global.seed)
else
global.generator.re_seed(global.seed)
end
return math.min(max, math.max(min, math.floor(global.generator(min, math.max(min, max + global.adseed)) % max) ) )
end
function set_spawns()
global.s = game.surfaces['nauvis'];
game.daytime = 0.9
table.each(global.forcesData, function(data)
MM_set_spawns(data);
end)
end
function set_starting_areas()
global.s = game.surfaces['nauvis'];
table.each(global.forcesData, function(data)
MM_set_starting_area(data);
end)
end
function make_team_option(player)
if global.player.gui.left.choose_team == nil then
global.frame = global.player.gui.left.add { name = "choose_team", type = "frame", direction = "vertical", caption = { "resources.team-choose" } }
table.each(global.forcesData, function(data)
global.frame.add { type = "button", caption = { 'resources.team-join', data.title }, name = 'choose_team_' .. data.name }.style.font_color = data.color
end)
global.frame.add { type = "button", caption = { "resources.team-auto-assign"}, name = "autoAssign" }
global.frame.add { type = "button", caption = { "resources.team-check-number" }, name = "team_number_check" }.style.font_color = { r = 0.9, g = 0.9, b = 0.9 }
end
end
function make_lobby()
game.create_surface("Lobby", { width = 96, height = 32, starting_area = "big", water = "none" })
end
function on_init(event)
make_lobby()
-- global information modified from initial config
if global.forcesData == nil then
global.forcesData = {}
end
if global.points == nil then
global.points = {
startingAreaRadius = 50, -- in this radius every tree will be destroyed
start = {
-- defines start point of map
x = 0,--math.random(220, 1060),
y = 0--math.random(220, 1060)
}, -- defines distance between spawn points for teams
distance = {
min = 1200,
max = 1800,
},
numberOfTrysBeforeError = 40 -- this is just a helper value (if we try to locate a non colliding point, we try it max XX times before we abort)
}
end
if global.distance == nil then
global.distance = 60 * 3
end
if global.big_distance == nil then
global.big_distance = 40 * 3 * 3
end
if global.researchMessage == nil then
global.researchMessage = {
enabled = true
}
end
if global.attackMessage == nil then
global.attackMessage = {
enabled = true,
interval = 5*MINUTES
}
end
if global.enableTeams == nil then
global.enableTeams = {
after = 30 * SECONDS, -- teams are eneabled after XX Seconds
messageInterval = 10 * SECONDS -- message interval /(when are the teams unlocked)
}
end
if global.teamBalance == nil then
global.teamBalance = {
enabled = true, -- wether team balance should be enabled or not
}
end
if global.teamMessageGui == nil then
global.teamMessageGui = {
enabled = true
}
end
if global.allianceGui == nil then
global.allianceGui = {
enabled = true,
changeAbleTick = 5 * MINUTES -- alliances could only be changed every XXX ticks
}
end
end
function on_player_created(event)
--Get the player that just joined
global.player = game.players[event.player_index]
--Take them to the lobby
global.player.teleport({ 0, 8 }, game.surfaces["Lobby"])
PrintToAllPlayers("A challenger has approached.")
--If the host player and configuration was not set.
if global.player.index == 1 and not isConfigWritten() then
PrintToAllPlayers('Creating configuration gui');
ConfigurationGui:createConfigurationGui(global.player);
end
--Print messages to new arrivals
if areTeamsEnabled() then
PrintToAllPlayers({"resources.please-select-team-msg"})
make_team_option(global.player)
else
PrintToAllPlayers({"resources.teams-have-not-been-set-msg"})
end
global.player.get_inventory(defines.inventory.player_ammo).clear();
global.player.get_inventory(defines.inventory.chest).clear();
global.player.get_inventory(defines.inventory.player_guns).clear();
global.player.get_inventory(defines.inventory.player_main).clear();
global.player.get_inventory(defines.inventory.player_quickbar).clear();
end
script.on_init(on_init);
script.on_event(defines.events.on_player_created, on_player_created);
function triggerTeamsEnabling()
global.TRIGGER_TEAMS_SECONDS = 10;
global.TICK_INTERVAL = global.TRIGGER_TEAMS_SECONDS * SECONDS;
PrintToAllPlayers({ "resources.teams-enable-wait-to-be-charted" })
-- PrintToAllPlayers('Wait for team areas to be charted');
global.checked_teams = {};
global.if_valid = function(tick)
PrintToAllPlayers("checking if valid")
for _, data in pairs(global.forcesData) do
PrintToAllPlayers(checked_teams[data.name])
if checked_teams[data.name] == nil then
PrintToAllPlayers("Checked teams is nil")
if is_area_charted(round_area_to_chunk_save(SquareArea(data.cords, global.big_distance)), s) == false then
PrintToAllPlayers("is area charted check")
--PrintToAllPlayers({ 'resources.teams-enable-not-charted-yet', data.title, seconds })
return false;
end
PrintToAllPlayers("set true for team")
--PrintToAllPlayers({ 'resources.team-area-charted', data.title })
checked_teams[data.name] = true;
end
end
return true;
end
global.tick_helper = function(tick)
table.each(global.forcesData, function(data)
MM_set_spawns(data);
MM_set_starting_area(data);
end)
setTeamsEnabled();
table.each(game.players, function(p)
make_team_option(p);
end)
end
register_tick_helper_if_valid('CREATE_TEAMS', global.tick_helper, global.tick_interval, global.if_valid);
end
function putPlayerInTeam(player, forceData)
global.s = game.surfaces['nauvis'];
global.player.teleport(game.forces[forceData.cName].get_spawn_position(global.s), global.s)
global.player.color = forceData.color
global.player.force = game.forces[forceData.cName]
player.gui.left.choose_team.destroy()
global.player.insert { name = "iron-plate", count = 8 }
global.player.insert { name = "pistol", count = 1 }
global.player.insert { name = "firearm-magazine", count = 10 }
global.player.insert { name = "burner-mining-drill", count = 1 }
global.player.insert { name = "stone-furnace", count = 1 }
Alliance:make_alliance_overlay_button(player);
TeamChat:make_team_chat_button(player);
PrintToAllPlayers({ 'teams.player-msg-team-join', global.player.name, forceData.title })
end
function couldJoinIntoForce(forceName)
if global.teamBalance.enabled == false then
return true;
end
global.check = {}
global.lastValue = 0;
global.onlyOne = false;
table.each(global.forcesData, function(data)
global.c = 0;
table.each(game.players, function(p)
if data.cName == global.player.force.name then c = c + 1 end
end)
check[data.cName] = global.c;
if global.lastValue == global.c then -- check if all teams have the same amount of players
global.onlyOne = true;
else
global.onlyOne = false;
end
global.lastValue = global.c
end)
if global.onlyOne == true then -- if all teams have the same amount of players, then it is possible to join this team
return true;
end
for k,v in spairs(check) do
return check[forceName] < v -- only join, if wanted force has fewer amount of players as the largest team
end
return true;
end
script.on_event(defines.events.on_tick,
function(event)
if isConfigWritten() then
if game.tick >= global.CONFIG_WRITTEN_TIME + global.enableTeams.after then
-- fix if game is saved and reload during generation
PrintToAllPlayers("Are teams enabled:")
PrintToAllPlayers(areTeamsEnabledStartup())
--teamsEnablingStarted = areTeamsEnabledStartup();
if areTeamsEnabledStartup() == false then
--teamsEnablingStarted = true;s
setTeamsEnabledStartup();
triggerTeamsEnabling();
end
elseif game.tick <= global.CONFIG_WRITTEN_TIME + global.enableTeams.after and game.tick % global.enableTeams.messageInterval == 0 then
global.enableTick = (global.CONFIG_WRITTEN_TIME + global.enableTeams.after) - game.tick;
global.seconds = Math.round(global.enableTick / SECONDS);
PrintToAllPlayers({ 'resources.teams-enable-in', global.seconds })
end
if (areTeamsEnabled()) then
tick_all_helper(event.tick);
tick_all_helper_if_valid(event.tick);
end
end
--fire armor
if event.tick % 60 == 0 then --common trick to reduce how often this runs, we don't want it running every tick, just 1/second
for index,player in pairs(game.connected_players) do --loop through all online players on the server
--if they're wearing our armor
if global.player.character and global.player.get_inventory(defines.inventory.player_armor).get_item_count("fire-armor") >= 1 then
--create the fire where they're standing
global.player.surface.create_entity{name="fire-flame", position=global.player.position, force="neutral"}
end
end
end
end
)
--Handling the gui clicks
script.on_event(defines.events.on_gui_click,
function(event)
global.s = game.surfaces.nauvis;
global.element = event.element
if global.element.valid ~= true then
return;
end
global.eventName = global.element.name;
global.player = game.players[event.player_index];
--Frame related
if global.eventName == 'next_step' then
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].saveStep, global.player);
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].destroyStep, global.player);
ConfigurationGui.currentStep = ConfigurationGui.steps[ConfigurationGui.currentStep].nextStep;
global.g = ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].createStep, global.player);
ConfigurationGui:createNextAndPrev(global.g);
elseif global.eventName == 'prev_step' then
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].saveStep, global.player);
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].destroyStep, global.player);
ConfigurationGui.currentStep = ConfigurationGui.steps[ConfigurationGui.currentStep].prevStep;
global.g = ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].createStep, global.player);
ConfigurationGui:createNextAndPrev(global.g);
elseif global.eventName == 'start_game' then
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].saveStep, global.player);
ConfigurationGui:try(ConfigurationGui.steps[ConfigurationGui.currentStep].destroyStep, global.player);
PrintToAllPlayers({ "lobby.lobby-msg-config-finished", game.players[1].name })
make_forces()
setConfigWritten();
elseif global.eventName == 'force_cancel' then
if global.player.gui.center.create_force ~= nil and global.player.gui.center.create_force.valid then
global.player.gui.center.create_force.destroy();
end
ConfigurationGui:createNextAndPrev(ConfigurationGui.steps.teams.createFrame(global.player));
--Force related
elseif global.eventName == 'force_save' then
if global.player.gui.center.create_force ~= nil and global.player.gui.center.create_force.valid then
if global.player.gui.center.create_force.caption ~= nil then
global.forcesData[global.player.gui.center.create_force.caption] = nil;
end
global.forceData = ConfigurationGui.steps.teams.getForceData(global.player.gui.center.create_force);
if global.forceData.cName ~= '' then
global.forcesData[global.forceData.cName] = global.forceData;
global.player.gui.center.create_force.destroy();
end
end
ConfigurationGui:createNextAndPrev(ConfigurationGui.steps.teams.createFrame(global.player));
elseif global.eventName == 'force_remove' then
global.parent = global.element.parent;
table.each(global.forcesData, function(forceData, k)
if global.parent.name == 'force_frame_' .. forceData.name then
global.forcesData[k] = nil;
end
end)
ConfigurationGui:createNextAndPrev(ConfigurationGui.steps.teams.createFrame(global.player));
elseif string.match(global.eventName,'force_edit_(.*)') ~= nil then
table.each(global.forcesData, function(forceData)
if global.element.valid and global.element.name == 'force_edit_' .. forceData.name then
if global.player.gui.center.teams_gui ~= nil then
global.player.gui.center.teams_gui.destroy();
end
ConfigurationGui.steps.teams.createForceGuiWithData(global.player, forceData);
return;
end
end)
elseif global.eventName == 'force_new' then
if global.player.gui.center.teams_gui ~= nil then
global.player.gui.center.teams_gui.destroy();
end
ConfigurationGui.steps.teams.createForceGui(p);
--team realated
elseif global.eventName == 'team_number_check' then
table.each(global.forcesData, function(data)
global.c = 0;
table.each(game.players, function(p)
if data.cName == global.player.force.name then global.c = global.c + 1 end
end)
global.player.print({ 'resources.player-msg-team-number', data.title, global.c })
end)
elseif global.eventName == 'autoAssign' then
global.check = {}
table.each(global.forcesData, function(data)
global.c = 0;
table.each(game.players, function(p)
if data.cName == global.p.force.name then global.c = global.c + 1 end
end)
global.check[data.cName] = global.c;
end)
for k,v in spairs(global.check, function (t,a,b) return t[a] < t[b] end) do
putPlayerInTeam(global.player, global.forcesData[k]);
break
end
elseif string.match(global.eventName, 'choose_team_.*') ~= nil then
table.each(global.forcesData, function(data)
if global.eventName == 'choose_team_' .. data.name then
if couldJoinIntoForce(data.cName) then
putPlayerInTeam(global.player, data);
else
global.player.print( { 'resources.player-msg-could-not-join', data.title } )
end
end
end)
end
end
) --end event handler for gui click
-- Normal Events for game changes (launching rocket, dieing)
script.on_event(defines.events.on_rocket_launched, function(event)
local force = event.rocket.force
if event.rocket.get_item_count("satellite") > 0 then
if global.satellite_sent == nil then
global.satellite_sent = {}
end
if global.satellite_sent[force.name] == nil then
game.set_game_state { game_finished = true, player_won = true, can_continue = true }
global.satellite_sent[force.name] = 1
else
global.satellite_sent[force.name] = global.satellite_sent[force.name] + 1
end
for index, player in pairs(force.players) do
if global.player.gui.left.rocket_score == nil then
local frame = global.player.gui.left.add { name = "rocket_score", type = "frame", direction = "horizontal", caption = { "score" } }
frame.add { name = "rocket_count_label", type = "label", caption = { "", { "rockets-sent" }, "" } }
frame.add { name = "rocket_count", type = "label", caption = "1" }
else
global.player.gui.left.rocket_score.rocket_count.caption = tostring(global.satellite_sent[force.name])
end
end
else
if (#game.players <= 1) then
game.show_message_dialog { text = { "gui-rocket-silo.rocket-launched-without-satellite" } }
else
for index, player in pairs(force.players) do
global.player.print({ "gui-rocket-silo.rocket-launched-without-satellite" })
end
end
end
end)
script.on_event(defines.events.on_research_started, function(event)
if global.researchMessage.enabled then
local force = event.research.force
PrintToAllPlayers({ 'teams.team-research-start', global.forcesData[force.name].title, { 'research-name' .. event.research.name } })
-- ResearchNotification.log('Team ' .. force.name .. ' has starting research ' .. event.research.name, force.name);
end
end)
script.on_event(defines.events.on_research_finished, function(event)
if global.researchMessage.enabled then
local force = event.research.force
PrintToAllPlayers({ 'teams.team-research-end', global.forcesData[force.name].title, { 'research-name' .. event.research.name } })
end
end)
script.on_event(defines.events.on_entity_died, function(event)
if global.attackMessage.enabled then
global.entity = event.entity;
global.force = event.force;
if global.force ~= nil and global.entity.force.name ~= 'neutral' then
if global.entity.force.name == 'enemy' then
if global.entity.name ~= "spitter-spawner"
and global.entity.name ~= "biter-spawner"
and global.entity.name ~= "small-worm-turret"
and global.entity.name ~= "medium-worm-turret"
and global.entity.name ~= "big-worm-turret"
then
return
end
end
if global.entity.force ~= nil and global.entity.force ~= global.force then
global.attacked = global.entity.force.name;
global.attackedFrom = global.force.name;
if global.attacked == 'enemy' then
global.attacked = 'Aliens'
end
if global.attackedFrom == 'enemy' then
global.attackedFrom = 'Aliens';
end
PrintToAllPlayers({ 'teams.team-attacked-by-team', global.attacked, global.attackedFrom })
end
end
end
end)
On_load still seems to be during the save-load cycle and I haven't gotten there yet.
-
- Burner Inserter
- Posts: 6
- Joined: Thu Jan 24, 2019 2:38 am
- Contact:
Re: Addressing Desync
It should be noted here that I was attempting to do a random call during make_forces which was causing desync. I still however want to verify how I can prevent desync when saving and loading.
Re: Addressing Desync
Nothing to do with desyncs, but you seem to be misusing the global table. You do not need to store local variables in global. In some places you are breaking your own code by using global too much. For example:TheOverwatcher wrote: ↑Tue Jan 29, 2019 2:03 amdo you recommend anything or see any other issues with the way it's currently laid out?
Code: Select all
for index, player in pairs(force.players) do
if global.player.gui.left.rocket_score == nil then
local frame = global.player.gui.left.add { name = "rocket_score", type = "frame", direction = "horizontal", caption = { "score" } }
frame.add { name = "rocket_count_label", type = "label", caption = { "", { "rockets-sent" }, "" } }
frame.add { name = "rocket_count", type = "label", caption = "1" }
else
global.player.gui.left.rocket_score.rocket_count.caption = tostring(global.satellite_sent[force.name])
end
end
-
- Burner Inserter
- Posts: 6
- Joined: Thu Jan 24, 2019 2:38 am
- Contact: