Client settings in multiplayer

So in singleplayer, it doesn’t matter that the gamplay settings (auto-loot, auto-rescue, default stockpile settings, etc.) are all done via the “host” settings. In multiplayer, this does matter. Most/all of these gameplay settings are normally considered player-specific, but as far as I can tell, the game doesn’t allow them to be. This results in really weird behavior when different players are trying to play with different settings: when players change the settings, those changes affect everyone in-game, but they don’t show up in other players’ settings!

Is there a way to have client settings that are savegame-independent (i.e., not relying on player-based saved variables)? If not, could you please, please, please add one? Even if you don’t retrofit all the existing settings as player-specific, we can handle that in ACE, as long as there’s a reasonable way to pull in player-specific data from outside the savegame (ideally something that doesn’t involve serializing as custom building templates).

1 Like

You can read and write stuff through the config API. If you run it on the client, you get/set it for that client. See the settings page JS.

Ahhh, interesting. When @DaniAngione and I tried testing some gameplay settings last night, we first tried our own ACE ones (which are apparently incorrectly configured), but we also tested the Auto Loot setting, and we experienced the issue I described above: one person changing the setting would apply that setting for both of us, but it wouldn’t update the checkbox for the other player.

I’m on mobile right now so I can’t check, but maybe other settings are properly configured and it’s just Auto Loot that’s messed up? Or maybe we did something wrong in our testing?

1 Like

Okay, so here’s the problem. All the settings properly set/save client-wise. However, Auto Loot, Auto Rescue, and Auto Queue are actually used server-side, which means they take the host’s setting into account regardless of what the client has set. Is there any way from the server to call a specific client? I guess maybe it can trigger an event that the client listens to, but that seems really inefficient if the goal is to check a client setting.

1 Like

You could have the client inform the server of its preference on startup and whenever the setting changes, and the server would keep track of each client’s last known value.

1 Like

Perfect, thank you! I just needed to think about approaching the problem in a different way instead of trying to approach what I thought was the solution in a different way.

So, I’m going to make this player_settings_service and patch all the places those Auto settings are used and have them query it rather than querying the config directly. Ideally this would make it into the base game, since even in the unlikely case that it’s intended behavior, it’s certainly not communicated to the players that those particular settings would only respect the host’s settings. But either way, ACE will have it, along with simpler ways for mods to add and use their own settings.

1 Like

It’s been a while since I looked at that code but I vaguely remember the client state or session services doing something like this already. Might want to check them out before potentially duplicating work. Might be worth checking with @linda as well for the same reason.

1 Like

Yeah, there is a client_state.lua controller for each client that contains various values that are unique to each client. There’s an example of a user_settings config in there if you take a look at the self._default_storage_filter_none. To get that value it calls the client_state service using stonehearth.client_state:get_default_storage_filter_none(player_id)).

1 Like

Thanks, I think I got it implemented mostly the way I want (it’s functional at least).

I patched the client_state and client_state_service files to include set/get functions and storage for player gameplay settings, which are populated initially by a new client service I made, gameplay_settings_service (which should really be renamed initial_gameplay_settings_service to better reflect what it does), which loads a JSON containing all relevant gameplay settings (organized by mod) and gets their initial config values, and then updated through settings.js whenever a player changes them. The JSON can specify base-game settings (the ‘stonehearth’ mod) to properly track a client player’s setting for Auto Loot, etc., as well as modders being able to specify all the details needed for settings.js to automatically generate the necessary settings controls (currently limited to boolean/checkboxes, but can easily be expanded to more types). The gameplay settings tab in the UI was also reconfigured to use a jQuery accordion, organizing settings by mod.

The biggest setback I ran into was trying to work around the Lua function radiant.util.get_config(...) since it only gets the config of the mod it’s being run from, but then I realized I could call'radiant:get_config', ...) and get any config.

Glad to heard it worked for you.

In util.lua there’s actually a radiant.util.get_global_config function that allows you to get configs from other mods. An example would be radiant.util.get_global_config('mods.stonehearth.always_clear_timers', false), where you’d replace stonehearth with whatever mod you need to get the config from, and always_clear_timers with the config name. Like the other function, the second argument is the default value you get if the config doesn’t exist.

1 Like

I don’t know how I missed that… but that’ll allow me to avoid using a deferred call. Thanks!

Paul, let me know if I can help with testing in ANY WAY, I’m really interested in getting this going. Thanks man!

It’s essentially fully implemented in a basic form in the current unstable version of ACE. Currently it supports boolean setting values represented graphically by checkboxes and possibly sliders for numerical setting values, though I haven’t tested the latter yet. Any type of value can be used for settings, the only limitation is in displaying it for the user and allowing them to change it.