Please Help with multiplayer error message

Place to get help with not working mods / modding interface.
User avatar
Kuxynator
Inserter
Inserter
Posts: 33
Joined: Wed Sep 23, 2020 5:02 pm
Contact:

Please Help with multiplayer error message

Post by Kuxynator »

Hello, I would need help.
115.735 Error ClientMultiplayerManager.cpp:1086: mod-Kux-CoreLib was not registered for the following nth_ticks when the map was saved but has registered > them as a result of loading: 13
115.735 Error ClientMultiplayerManager.cpp:99: MultiplayerManager failed: "" + multiplayer.script-event-mismatch + "
" + "
mod-Kux-CoreLib"
115.739 Info ClientMultiplayerManager.cpp:610: UpdateTick(20123018) changing state from(ConnectedLoadingMap) to(Failed)
I do not understand was the error means:
"was not registered for the following nth_ticks when the map was saved but has registered them as a result of loading: 13"
why must the event be registered when the map was saved?
I know I have to re-register events which was registered when the map was saved, but not vice versa.

maybe the code helps and I make some things wrong for multiplayer
control.lua

Code: Select all

script.on_nth_tick(13, function(event)
  print("one time event after load")  
  script.on_nth_tick(13, nil)
end)
Thanks
Rseding91
Factorio Staff
Factorio Staff
Posts: 14265
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Please Help with multiplayer error message

Post by Rseding91 »

The error message is meant to let you know that what you're attempting to do is something you aren't supposed to do.

Because of the way multiplayer works; the game is not supposed to change state in any way between save -> exit -> load EXCEPT in the case that mods have been added, removed, or updated. But; those cases are never supposed to happen while playing multiplayer.

In the case of mods being added, removed, or updated the event https://lua-api.factorio.com/latest/Lua ... on_changed will be fired to let mod(s) do any fix-ups they need to do.
If you want to get ahold of me I'm almost always on Discord.
User avatar
Kuxynator
Inserter
Inserter
Posts: 33
Joined: Wed Sep 23, 2020 5:02 pm
Contact:

Re: Please Help with multiplayer error message

Post by Kuxynator »

Thanks for your response :-)
But I do not understand how my code changesthe state between save -> exit -> load
Does this mean, if I deregister the event on tick 13, then the game ist saved, i must not register it again in main part of control.lua?
azaghal
Inserter
Inserter
Posts: 36
Joined: Sat Jun 27, 2020 11:13 am
Contact:

Re: Please Help with multiplayer error message

Post by azaghal »

Since I just got hit by this one, maybe I can at least try to shed some light on what I think happens. And in some ways, I am doing something similar where I register event handler for on_nth_tick, but only when required (my mod does some processing of delivered equipment, and if there's nothing more to process deregisters itself in order to be UPS-friendly).
  1. Let's say you register on_nth_tick handler in control.lua.
  2. Server starts up, runs control.lua, resulting in handler getting registered.
  3. Your on_nth_tick handler at some point decides to deregister itself. At this point the game has no handler registered for on_nth_tick server-side.
  4. Now a player comes in and decides to join the game. The control.lua gets executed on client side, which results in on_nth_tick handler getting registered, but only on the client side. At this point you have server and client having different set of handlers registered (which cannot be allowed since Factorio requires state to be the same on both server and all clients, including registered handlers).
The way I was able to fix this on my side is to have the logic for conditional registration inside of the on_load handler. In my case this worked fine, since my on_nth_tick handler normally only gets registered as response to player actions, and it will deregister itself on its first run if there is no processing left. So, in my case I don't have to register it during initialisation (but otherwise I guess you'd use the on_init handler for when mod gets introduced into savegame).

Truth be told, that error message is a bit hard to parse, and I did not understand what the problem is initially as well, and had to do play around with the code a bit before I knew what to do :)

P.S.
You may have already figured this out by yourself, but I think the explanation could be useful if someone else (like my future self) runs in the same issue :)
Pi-C
Smart Inserter
Smart Inserter
Posts: 1726
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: Please Help with multiplayer error message

Post by Pi-C »

In multiplayer, you will get desyncs when the game state of a client differs from that of the server. Therefore, you shouldn't use things like:

Code: Select all

local function init()
	-- Initialize tables
		...
	-- Set flag
	GAME_INITIALIZED = true
end

script.on_init(function()
	init()
end)

script.on_configuration_changed(function(event)
	if not GAME_INITIALIZED  then
		init()
	end
end)
The problem with this is that the flag GAME_INITIALIZED is a global variable (i.e. you can read it from any file required in your control.lua) for only the local player: When the first player starts a game, the flag will be set. When the second player joins, the flag is set for player 1 but not set for player 2, so you get a desync.

In order to get this to work you must make sure that the flag is saved with the game, by storing it in your table "global":

Code: Select all

local function init()
	-- Initialize tables
		...
	-- Set flag
	global.GAME_INITIALIZED = true
end

script.on_init(function()
	init()
end)

script.on_configuration_changed(function(event)
	if not global.GAME_INITIALIZED  then
		init()
	end
end)

This example may not be ideal, but I use similar constructs for registering optional events:

Code: Select all

local function on_tick(event)
	if global.cars and next(global.cars) then
		for c, car in pairs(global.cars) do
			-- Do stuff
		end
	else
		script.on_event(defines.events.on_tick, nil)
	end	
end

script.on_event(defines.events.on_built_entity, function(event)
	if event.created_entity.type == "car" then
		global.cars[event.created_entity.unit_number] = event.created_entity
		script.on_event(defines.events.on_tick, on_tick)
	end
end)

local function check_optional_events()
	if global.cars and next(global.cars) then
		script.on_event(defines.events.on_tick, on_tick)
	end
end

script.on_configuration_changed(function(event)
	check_optional_events()
end)

script.on_load(function()
	check_optional_events()
end)
This will enable the on_tick event when an entity based on a "car" prototype is built. We don't need to do anything in script.on_init because this will only run when a game is started, and at that point no player could have built an entity yet. When you continue a saved game (script.on_load and script.on_configuration_changed), the handler for on_tick will be registered if a player has already built one of the wanted entities (global.cars exists, and next(global.cars) confirms that the table is not empty). The event handler will be unregistered again in function on_tick if the table global.cars has been removed completely or is empty.

So if you want to enable certain events only if needed, you should depend on the contents of your mod's table "global" (which is saved with the game, and is therefore shared by the server and all clients)!
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Post Reply

Return to “Modding help”