Tabletop Simulator

Tabletop Simulator

Not enough ratings
Fix for XML Input Fields not Synchronizing to All Clients
By Capellan
If your XML UIs aren't syncing what's typed to everyone, there's an easy fix. Also, a generic Boilerplate for XML UI is provided.
   
Award
Favorite
Favorited
Unfavorite
The Fix
If you want an InputField in your XML UI to synchronize to all clients, it must have an "onValueChanged" handler and an "id" field, e.g.

<InputField id="4" onValueChanged="onValueChanged" />

The Lua code for the object must then implement that handler, and that handler must update the InputField's "Text" attribute. For example:

function onValueChanged(player, value, id) self.UI.setAttribute(id, "Text", value) end

Note that this is why the element must have an "id", so that the code can assign back to its attribute. Note also that `setValue` WILL NOT work here, even though you might expect it to.

This behaviour is somewhat unexpected. I've filed a bug report for it here, if you wish to upvote it or comment in support: https://tabletopsimulator.nolt.io/2262
Boilerplate for a synchronized, saved XML UI
Attached here is some boilerplate for an XML UI that implements onSave and onLoad, and synchronizes those values above so updates can be seen by all players. It's essentially the basis of the record sheets for the Gensou Narratograph mod. Feel free to use it as a jumping off point.

XML:
<Defaults> <InputField onValueChanged="valueChanged" /> <Toggle onValueChanged="toggleChanged" /> </Defaults> <!-- Your UI here... -->

Lua:
local state = { inputs = {}, toggles = {} } function applyState() for id, v in pairs(state.inputs) do self.UI.setAttribute(id, "Text", v) self.UI.setValue(id, v) end for id, v in pairs(state.toggles) do self.UI.setAttribute(id, "isOn", v or nil) end end function valueChanged(player, value, id) state.inputs[id] = value self.UI.setValue(id, value) -- Updating the value doesn't update the text content because lmao self.UI.setAttribute(id, "Text", value) end function toggleChanged(player, isOn, id) state.toggles[id] = isOn self.UI.setAttribute(id, "isOn", isOn or nil) end function onLoad(save_state_string) if save_state_string ~= "" then state = JSON.decode(save_state_string) applyState() end end function onSave() return JSON.encode(state) end

This uses the `Defaults` block to apply these handlers to all input elements by default. Classes defined in `Defaults` blocks can also define `onValueChanged` attributes, which is useful if you have multiple elements that do similar things. Elements or classes that need more or different functionality can of course supply their own onValueChanged handlers that call `valueChanged` to get the saving and syncing.

Happy Hacking! TTS has its share of rough edges but a little scripting can go a long way!