world_state.onDeserialize restores per-campaign settings after __original(_in):
q.onDeserialize = @(__original) function( _in )
{
__original(_in); // World.Flags, EntityManager, rosters, every item_container
...
::MSU.System.ModSettings.flagDeserialize(_in);
}
onSerialize is the mirror image — it calls flagSerialize(_out) before __original.
So for the whole duration of world deserialization a per-campaign setting still holds the
global value from ModSettings.sav. Any mod that reads a setting from a hook reachable
during load sees the wrong value.
Concrete case: Challenges mod hooks item_container.equip and refuses items banned by a setting, i.e. "only light shields". This causes the shield to go off a bro to stash on game load. Campaign has the setting at "allow all shields", which is only read after. In-session load is fine, since the setting object already holds the campaign value. However, if you load other campaign from within already loaded one it may break in even more surprising manner.
I realise ::World.Flags only exists after World.Flags.onDeserialize(_in), which is the
first line inside __original, so the read can't simply move up — it would need a
finer-grained hook that runs between World.Flags and EntityManager.
Workaround for mod authors, for the record: guard on ::MSU.Serialization.isLoading().
MSU 1.9.0, also present on master.
world_state.onDeserializerestores per-campaign settings after__original(_in):onSerializeis the mirror image — it callsflagSerialize(_out)before__original.So for the whole duration of world deserialization a per-campaign setting still holds the
global value from
ModSettings.sav. Any mod that reads a setting from a hook reachableduring load sees the wrong value.
Concrete case: Challenges mod hooks
item_container.equipand refuses items banned by a setting, i.e. "only light shields". This causes the shield to go off a bro to stash on game load. Campaign has the setting at "allow all shields", which is only read after. In-session load is fine, since the setting object already holds the campaign value. However, if you load other campaign from within already loaded one it may break in even more surprising manner.I realise
::World.Flagsonly exists afterWorld.Flags.onDeserialize(_in), which is thefirst line inside
__original, so the read can't simply move up — it would need afiner-grained hook that runs between
World.FlagsandEntityManager.Workaround for mod authors, for the record: guard on
::MSU.Serialization.isLoading().MSU 1.9.0, also present on master.