Lua only fire on local client

Discussion of Lua and LuaWML support, development, and ideas.

Moderators: Forum Moderators, Developers

Post Reply
User avatar
Azeal
Posts: 97
Joined: July 24th, 2012, 8:19 am

Lua only fire on local client

Post by Azeal » November 20th, 2012, 12:52 pm

I'm making a menu item that plays a track and I want it to only apply to the client that selected it.
So far I have this

Code: Select all

    [set_menu_item]
        id=playlist_menu
        image=icons/music_icon.png
        description= _ "Select a Playlist"
        [command]
            [message]
                speaker=narrator
                side_for=$side_number
                    [option]
                        message={MENU_IMG_TXT "icons/music_icon.png" "Crock Test 1"}
                        [command]
                            [lua]
                                code=<<
                                    wesnoth.fire("music", { name="crock_-_optic_deception.ogg", play_once="yes", immediate="yes" })
                                >>
                            [/lua]
                        [/command]
                    [/option]
            [/message]
        [/command]
    [/set_menu_item]
how do I make the LUA code only apply to the local client?

User avatar
Elvish_Hunter
Forum Moderator
Posts: 1395
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: Lua only fire on local client

Post by Elvish_Hunter » November 20th, 2012, 8:42 pm

Azeal wrote:how do I make the LUA code only apply to the local client?
Usually UMC authors should seek exactly the opposite, that is having everything correctly synchronized, otherwise OOS errors may occur.
That said, the first thing to try is using an unsafe multiplayer event. Here you can find a list of MP safe events, so you'll need one that isn't on this list: the prestart or start event should do.
The second thing that I'd try will be (at least for testing purposes) avoiding the [set_menu_item] thing, and place the [message] block directly inside the event. This way, you'll have one less thing to worry about for now. Also, [set_menu_item] can be used to force syncronization (with the option needs_select=yes), so if you want to use it you'll need to create a custom Lua dialog to invoke instead of [message], as Lua dialogs are MP-unsafe if wesnoth.synchronize_choice() is not used.
The third thing is not related to synchronization, but about your Lua command. Instead of relying on wesnoth.fire (outdated practice), you can just call directly the corresponding Lua function, that is wesnoth.set_music():

Code: Select all

wesnoth.set_music { name="crock_-_optic_deception.ogg", play_once="yes", immediate="yes" }
This won't solve your problem, but instead of calling a function that calls a WML tag that calls this function, you'll call directly the function.
Current maintainer of these add-ons:
1.14: The Sojournings of Grog, A Rough Life, The White Troll (co-author), Wesnoth Lua Pack
1.12: Children of Dragons

User avatar
zookeeper
WML Wizard
Posts: 9740
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: Lua only fire on local client

Post by zookeeper » November 20th, 2012, 10:32 pm

Elvish_Hunter wrote:That said, the first thing to try is using an unsafe multiplayer event. Here you can find a list of MP safe events, so you'll need one that isn't on this list: the prestart or start event should do.
Well, those events will still get triggered on every client, so they won't do. Them not being MP safe merely means that if you use the RNG or present [option]s in a prestart/start event, the results/choices won't be synchronized. In case of [option]s, I think the other clients would simply pick the first option.

I don't think there's a workaround using start events and [option]s which would allow you to do what he wants to do, at least not for more than two players.

Anonymissimus
Inactive Developer
Posts: 2458
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Lua only fire on local client

Post by Anonymissimus » November 21st, 2012, 12:12 am

First, let's distinguish between local and active client.
There always is exactly one side in this strictly turn based game which can currently move and call [set_menu_item]s, which is the side of the currently active client. All other sides cannot do either of these during that.
So, what you can do (I think) is make this music play only on the currently active client, namely by putting that code into
a function which you pass to wesnoth.synchronize_choice. Look up its documentation. Note that this is sort of a hack, as it's using that function not quite for what it is intended for. I'm also doing it in SoW anyway.

EDIT
zookeeper wrote:Well, those events will still get triggered on every client, so they won't do. Them not being MP safe merely means that if you use the RNG or present [option]s in a prestart/start event, the results/choices won't be synchronized.
IIRC you suggested in another thread which I recall to use the name=select event to create out-of-sync variables. That event actually is triggered only on the active (not local, I think, but needs a test) client.
So, it should be usable for solving the problem. The wesnoth.sync_choice method is cleaner however, and it would not make much sense to the player why he needs to select a unit in order to trigger music.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign

User avatar
Azeal
Posts: 97
Joined: July 24th, 2012, 8:19 am

Re: Lua only fire on local client

Post by Azeal » November 21st, 2012, 4:52 am

I've solved this (for now) using a select event. The set_menu_item is wrapped in it and it generates an id that includes $side_number (thanks to zookeeper), so you don't need to select a unit to fire the music, just to create the menu item. Also this does cause an OOS message. I've had a look through the Lua documentation particularly the syncronize_choice but I'm having a hard time grasping it. From what I gather on the wiki page syncronize_choice is used to recover WML that was executed on a single client, and then sync it to other clients (at least the example code).
Elvish_Hunter wrote:Lua dialog to invoke instead of [message], as Lua dialogs are MP-unsafe if wesnoth.synchronize_choice() is not used.
can a Lua dialog contain options and commands? If so wouldn't using Lua dialog instead of messages achieve the result I'm looking for (cause the command to only execute on a single client)?

Another problem is that any work around will probably cause an OOS message, that while is harmless, may be annoying. Is there anyway to make it so a client will ignore the OOS and not pop up with a message?

Anonymissimus
Inactive Developer
Posts: 2458
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Lua only fire on local client

Post by Anonymissimus » November 21st, 2012, 5:26 pm

Azeal wrote:I've had a look through the Lua documentation particularly the syncronize_choice but I'm having a hard time grasping it. From what I gather on the wiki page syncronize_choice is used to recover WML that was executed on a single client, and then sync it to other clients (at least the example code).
Yes. The point is that the code passed to sync_choice in form of a function is executed only on the active client, which is what you want. The result could then be passed to the other clients, but your use case doesn't need that. The wml can remain unchanged, though IIRC the side_for= key in [message] is ignored in case that that message has an [option]. Such messages can only be shown on the currently active client. Here's the lua part from above modified accordingly. (untested):

Code: Select all

code= <<
    local foo = function()
        wesnoth.fire("music", { name="crock_-_optic_deception.ogg", play_once="yes", immediate="yes" })
    end
    wesnoth.synchronize_choice(foo)
>>
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign

User avatar
Pentarctagon
Forum Administrator
Posts: 4056
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: Lua only fire on local client

Post by Pentarctagon » November 21st, 2012, 6:44 pm

This is working code that I have from this thread:

Code: Select all

                  [lua]
                    code=<<
                    
                    local function foo()
                    local has_file = false
                    wesnoth.fire("music", { name="$music_text", append="$music_append", play_once="$music_once", immediate="yes" })
                    return { has_file = has_file }
                    end
                    
                    local has_file = wesnoth.synchronize_choice(foo).has_file
                    
                    >>
                  [/lua]
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code

User avatar
Azeal
Posts: 97
Joined: July 24th, 2012, 8:19 am

Re: Lua only fire on local client

Post by Azeal » November 22nd, 2012, 4:32 am

Anonymissimus wrote:
Azeal wrote:I've had a look through the Lua documentation particularly the syncronize_choice but I'm having a hard time grasping it. From what I gather on the wiki page syncronize_choice is used to recover WML that was executed on a single client, and then sync it to other clients (at least the example code).
Yes. The point is that the code passed to sync_choice in form of a function is executed only on the active client, which is what you want. The result could then be passed to the other clients, but your use case doesn't need that. The wml can remain unchanged, though IIRC the side_for= key in [message] is ignored in case that that message has an [option]. Such messages can only be shown on the currently active client. Here's the lua part from above modified accordingly. (untested):

Code: Select all

code= <<
    local foo = function()
        wesnoth.fire("music", { name="crock_-_optic_deception.ogg", play_once="yes", immediate="yes" })
    end
    wesnoth.synchronize_choice(foo)
>>
works perfectly, thank you very much!

Post Reply