Accessing Global on new save in multiplayer

Place to get help with not working mods / modding interface.
User avatar
Muppet9010
Filter Inserter
Filter Inserter
Posts: 283
Joined: Sat Dec 09, 2017 6:01 pm
Contact:

Accessing Global on new save in multiplayer

Post by Muppet9010 »

I made a mod that runs fine in single player and then tested it in multiplayer. While I thought I had obeyed the rules in the API data lifecycle, the mod worked fine, until I tried to rejoin a saved and reloaded MP game and got unsafe for multiplayer when loading/saving error.

I have tried different code combinations from looking at other mods and while there are no errors anymore the mod appears to fail to run the start_up() function properly on a multiplayer server as none of the global objects exists or the registered API commands. However, it works fine in a single player server

I originally didn't have any on_tick event as I just need to initialise and then react to events, however, I tried to use on_tick to get around the issue and at the same time added the extra "if not global.state.xxxx" into all function calls that the start_up() function calls. i.e. global.state.disable_satelite

Can anyone point where I have gone wrong?

The control.lua code is below

Code: Select all

require("prototypes.utility.utils")
require("constants")

require("prototypes.commands")
require("prototypes.orders")
require("prototypes.gui")

script.on_init(function() on_init() end)
script.on_load(function() on_load() end)
script.on_configuration_changed(function() on_init() end)
--script.on_event({defines.events.on_tick}, function() on_init() end)
script.on_event({defines.events.on_player_created}, function(event) on_player_created(event) end)
script.on_event({defines.events.on_gui_click}, function(event) on_gui_click(event) end)

function on_init()
	start_up()
	sisyphean.commands.register()
end 

function on_load()
	sisyphean.commands.register()
end

function start_up()
	generate_global_state()
	generate_global_structure()
	sisyphean.orders.initialise()
	sisyphean.order_item.initialise()
	disable_satelite_dialog()
end

function generate_global_state()
	if not global.state then global.state = {} end
	if not global.state.order_target then
		global.state.order_target = tonumber(settings.startup[sisyphean.setting_name.order_target].value)
	end
	if not global.state.started then 
		global.state.started = false
	end
	if not global.state.finished then 
		global.state.finished = false
	end
	if not global.state.orders_completed then
		global.state.orders_completed = 0
	end
	if not global.state.current_order_id then
		global.state.current_order_id = 0
	end
end

function generate_global_structure()
	if not global.orders then global.orders = {} end
end

function disable_satelite_dialog()
	if not global.state.disable_satelite then
		if remote.interfaces["silo_script"] then
			global.state.disable_satelite = true
			remote.call("silo_script","set_show_launched_without_satellite", false)
			remote.call("silo_script","set_finish_on_launch", false)        
		end
	end
end

function on_player_created(event)
	local player = game.players[event.player_index]
	sisyphean.gui.add_gui_for_player(player)
end

function on_gui_click(event)
	sisyphean.gui.gui_clicked(event)
end
The full mod is attached.
This was done on 0.16.39 client and server (2nd pc in headless mode).

As a side note, I am a c#, database and web developer and only have limited experience with LUA.
Attachments
sisyphean_deliveries_0.0.1.zip
mod
(34.54 KiB) Downloaded 75 times
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Accessing Global on new save in multiplayer

Post by bobingabout »

I would need to examine this closer to see if there's any issues, but the one thing I do know right now, is that I dislike the fact that you're using an on_load.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5211
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Accessing Global on new save in multiplayer

Post by eradicator »

commands.add_command is safe to (==recommended to) call outside of any event, this makes it unconditional unless there's another mod trying to add the same command. As commands are like event handlers in that they're not part of the global state and thus not synced. (Unless you're actually dynamically adding/removing commands. Did only skim over the code).

Other than that...do you have any dynamic/conditional event handlers?
User avatar
Muppet9010
Filter Inserter
Filter Inserter
Posts: 283
Joined: Sat Dec 09, 2017 6:01 pm
Contact:

Re: Accessing Global on new save in multiplayer

Post by Muppet9010 »

Thank you for the suggestions, they got me thinking and I realised a few things (may be useful if someone else finds this thread):
- API Commands aren't saved into global and so have to be re-generated on each map load. This explained some of my failing tests.
- Remote interface command to affect the core game doesn't get saved between loads, so have to disable the silo script on each load.
- carefully review what I had in on_load and on_init in relation to global and game variables
- that when in-game you can't run mod functions via "/c" due to the scope and this also causes objects to appear empty via "/c". added logging to text file to confirm values in these cases.

My updated code below that doesn't require on_tick seems to work for my SP and MP testing with rejoining, save, loading and restarting the server from the save.

Code: Select all

require("prototypes.utility.utils")
require("constants")

require("prototypes.commands")
require("prototypes.orders")
require("prototypes.gui")



local function generate_global()
	global = global or {}
	if global.state == nil then global.state = {} end
	if global.state.order_target == nil then
		global.state.order_target = tonumber(settings.startup[sisyphean.setting_name.order_target].value)
	end
	if global.state.started == nil then 
		global.state.started = false
	end
	if global.state.finished == nil then 
		global.state.finished = false
	end
	if global.state.orders_completed == nil then
		global.state.orders_completed = 0
	end
	if global.state.current_order_id == nil then
		global.state.current_order_id = 0
	end
	if global.orders == nil then global.orders = {} end
end

local function start_up()
	sisyphean.order_item.initialise()
	sisyphean.commands.register()
	disable_satelite_dialog()
end

local function on_player_created(event)
	local player = game.players[event.player_index]
	sisyphean.gui.add_gui_for_player(player)
end

local function on_gui_click(event)
	sisyphean.gui.gui_clicked(event)
end

function disable_satelite_dialog()
	if remote.interfaces["silo_script"] then
		remote.call("silo_script","set_show_launched_without_satellite", false)
		remote.call("silo_script","set_finish_on_launch", false)        
	end
end


script.on_init(function() 
	generate_global()
	start_up()
end)
script.on_load(function() 
	start_up()
end)
script.on_configuration_changed(function() 
	generate_global()
	start_up()
end)
script.on_event({defines.events.on_player_created}, function(event) on_player_created(event) end)
script.on_event({defines.events.on_gui_click}, function(event) on_gui_click(event) end)
script.on_event(defines.events.on_rocket_launched, function(event)
	sisyphean.orders.rocket_launched_event(event.rocket, event.silo)
end)
Post Reply

Return to “Modding help”