From The Battle for Wesnoth Wiki

The wesnoth.sync module contains functions to synchronize data between players. This isn't only for multiplayer - single-player replays will break unless choices are synchronized between the player and the viewer.


  • wesnoth.sync.evaluate_single([description], function, [ai_function], [for_side]) → result

Recovers a WML table that was computed on one client only or was stored in a replay. The actual computation is performed by the function passed as the first function argument, assuming that the client is the side currently playing. For all the other clients, the function will not be called. An optional second function can be passed; if present, it will be used instead of the first one when the client happens to be an AI (hence not enable to interact with a user interface).

local result = wesnoth.sync.evaluate_single(
    -- Called only on the client handling the current side, if it is a human.
    local choice = 0
      some_dialog_cfg, nil,
        choice = window.some_list.value
    return { value = choice }
    -- Called only on the client handling the current side, if it is an AI.
    return { value = math.random(some_list_size) }
wesnoth.interface.add_chat_message(string.format("Selected item: %d", result.value))

Note: The return value must be a valid WML table - the same kind of thing you could store to a WML variable, and not, for instance, a proxy unit, anything else that uses metatables, or a lua table with another table as the value of a string attribute. Unlike other lua functions, wesnoth.sync.evaluate_single will not throw an error if the table is invalid, but will silently strip out the contents of any invalid subtag.

Note: This function should only be called from a synchronized event; it may silently fail (or silently fail to synchronize) when called from an unsynced event.

When wesnoth is running in debug mode (e.g. --debug flag on command line) evaluate_single will chat a "Lua Warning" if it finds that the table returned was partially invalid.

The optional first argument description is a string describing the type of the user input. This is displayed to the other clients while one client executes the passed function. Defaults to "input".

The final argument specifies on which side the function should be evaluated. Defaults to the currently playing side. If the specified side is empty/null controlled, the engine will choose another side.


  • wesnoth.sync.evaluate_multiple([description], function, [default_function], [for_sides]) → result map

Similar to the singular form above, this function takes a function parameter and evaluates it on the specified sides. It takes the following arguments:

  • An optional translatable string describing the type of the user input. This is displayed to the other clients while the specified clients execute the passed function. Defaults to "input"
  • A function that evaluates the choice, returning a WML table. Unlike above, this function is called for AI and human sides (use if controller == "ai" for checking if it is an AI side)
  • An optional function for evaluating the choice in case this side was null controlled. If this function is called, it is called on all clients (unlike the first passed function) defaults to a function returning an empty table.
  • An array of integers specifying on which sides this function should be evaluated. The function is evaluated on all passed sides, and each side may only appear once in this array. All specified sides execute the function simultaneously.

Note: This function should only be called from a synchronized event; it will always error-out when called from an unsynced event.

This function returns a table with integer as keys and WML tables as values. The keys are the sides where that action was evaluated, and the values are the values computed by the passed function on each side.

local _ = wesnoth.textdomain "my-scenario"
local result = wesnoth.sync.evaluate_multiple(
  local options = {_"No", _"Yes"}
  local result = gui.show_narration({message = _ "Are you sure you want to play this game?"}, options)
  return { value = tostring(options[result]) }
wesnoth.message("Player 1 wants to play: " .. result[1].value)
wesnoth.message("Player 2 wants to play: " .. result[2].value)


  • wesnoth.sync.run_unsynced(func)

Calls the given function in a unsynced context. In particular, while executing that function, random results will not be synced in mp. The function is called with no arguments, and any return values are ignored.


  • wesnoth.sync.invoke_command(command_name, cfg)

Invoke a custom synced command, which is registered in the wesnoth.custom_synced_commands table. You can pass an arbitrary WML table as arguments.

This page was last edited on 7 July 2021, at 02:49.