uhm, ok. I'm no programer, so at least this first time reading I did not understood anything from what you wrote =/

But I would be greateful if we first could clarify the initial issue... I can't imagine that simply calling "InitUnit()" alon in a lua script is already causing desync. I have a lot of mods active in multiplayer that do spawn (init) units, without desyncing. Or is it only the combination of spawn and directly kill the same unit afterwards?
Eg a "convenient start" mod that let you start with "super settles" and it will replace them after first turn with normal settlers:
Code:
for unit in pPlayer:Units() do
if (unit:GetUnitType() == GameInfoTypes["UNIT_SUPERSETTLER"]) then
pSettler = pPlayer:InitUnit(GameInfoTypes["UNIT_SETTLER"], unit:GetX(), unit:GetY(), GameInfoTypes["UNITAI_SETTLE"], unit:GetFacingDirection())
pSettler:SetEmbarked(unit:IsEmbarked())
unit:Kill(false, -1)
end
end
this code does not cause desync.
So I still assume the problem is the "button" from a custom UI you pressed ?!
More precisely, it is not the method invoking itself causing desync.
CIV5 maintains lists (actually a CPP container named "set" that ensures no duplicate elements are inserted) of units/cities/plots and other game objects on all the players' PC. At the end of each turn the game will ask all the clients to check their lists one by one. If a unit in the Non-host player's list does not exists in the host player's, it will cause a re-sync and all the lists will be change to be identical with the host-player. This might be what the game is doing when showing you a loading screen.
Therefore, some invokes of the setter methods will not cause desync:
The code you posted might be executed by all the players since it is invoked in AI turns or invoked at the end of a turn that all the players will call them at the same time with the same initial game state. In this case, all the player execute the same setter method like SetEmbarked and InitUnit with their the same initial state of their unit lists, then the adding (InitUnit ) and changing (SetEmbarked) are executed with same arguments. If initial states and the operations on different players' PC are same, the final version of the lists are also identical, so the game will not desync.
You mentioned the button will cause desync. It is obvious that any time when the button (especially those only show when clicking a unit) is pressed, the relating function is called by only one of the players. I can not select other player's units and click their buttons.
If the button is to replace your swordsman with legion, a non-host player pressing it will delete the swordsman and add a legion in his unit list, with the host's unit list unchanged. At the end of this turn, the game will iterate through his unit list, find the legion and notice that is does not exist in the host's unit list, then a desync is triggered.
If you transform all the swordsman to legion by calling unit:Kill and Player:InitUnit at the end of each turn, the swordsman's removal and the legion's emergence are executed on host's unit list, so in the next turn the legion will not be erased.
So a solution is to ask all the players to call the setter methods.