Skip to content

Per-campaign settings are restored after the world is deserialized #512

Description

@Suor

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions