Irdya - Wesmere Reference Implementation

Discuss the development of other free/open-source games, as well as other games in general.

Moderators: Forum Moderators, Developers

User avatar
pauxlo
Posts: 1046
Joined: September 19th, 2006, 8:54 pm

Re: Irdya - Wesmere Reference Implementation

Post by pauxlo » April 14th, 2016, 8:59 pm

fabi wrote:But what happens if an add-on is depending and extending on a parent one?
Those are most likely to want reading/writing the parent's variables.
Maybe for this case there should be a way to qualify which addon's variable you are trying to read/write? (namespacing like addon.var, for example.)

fabi
Developer
Posts: 1223
Joined: March 21st, 2004, 2:42 pm
Location: Germany

Re: Irdya - Wesmere Reference Implementation

Post by fabi » April 14th, 2016, 9:27 pm

pauxlo wrote:Maybe for this case there should be a way to qualify which addon's variable you are trying to read/write? (namespacing like addon.var, for example.)
Yes. And the good news are:
Lua comes with exactly that feature.
And you also guessed the exact syntax for accessing the variable.

Although Pentarctagon's globals problem might be avoided.
In most cases we can just use local variables.

Let's see how we can avoid globals:

Code: Select all

PreStart: ->
    local bar -- or just: bar = "something"
    event
        type: "Start"
        command: ->  
            foo = "Hi"
            bar = "hello"
    event
        type: "Turn1"
        command: ->
            assert(foo == nil)
            assert(bar == "hello")
"Wesnoth has many strong points but team and users management are certainly not in them." -- pyrophorus

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

Re: Irdya - Wesmere Reference Implementation

Post by Pentarctagon » April 16th, 2016, 3:29 pm

So to have everything be "add-on local", I would just need to wrap all the WSL in my add-on in an event that happens before the events I'm using? That seems like it might be a problem for using preload events though.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code

fabi
Developer
Posts: 1223
Joined: March 21st, 2004, 2:42 pm
Location: Germany

Re: Irdya - Wesmere Reference Implementation

Post by fabi » April 17th, 2016, 4:33 pm

Pentarctagon wrote:So to have everything be "add-on local", I would just need to wrap all the WSL in my add-on in an event that happens before the events I'm using?
I don't know the exact shape of your add-on.
I guess the music player comes as a mp modification?

The trick is not to wrap it into events but to have the variable declared in a context which is shared by all code that wants to access it.
Wrapping into events is only one way to do that.

Another example:

Code: Select all

foo = "bar"

scenario
    Start: ->
        assert(foo == "bar")
So we see that we can declare local variables just before the scenario function is called and have access to them in all events.
If you call 'scenario' twice or more in the same file all the scenarios' events have access to it (Assuming the call is below the declaration).
That seems like it might be a problem for using preload events though.
So PreLoad events are not a problem.
Although, most likely, PreLoad events won't make it into Irdya or only as some sort of backward compatibility cruft.
The Wesmere server host (the c++ thing that executes Irdya) will safe the game state by just dumping the Lua interpreter's state to disc.

When the Lua state is restored everything is like it was in the last session.
I think that pretty much makes the PreLoad event obsolete since it is used to workaround parts of the game state not being saved by the Wesnoth engine.
"Wesnoth has many strong points but team and users management are certainly not in them." -- pyrophorus

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

Re: Irdya - Wesmere Reference Implementation

Post by Pentarctagon » April 17th, 2016, 5:11 pm

I would not have expected that to work, actually, what with [scenario] being a "top level tag" in WML. Does that mean variables can be declared just about anywhere?

As for preload events, I don't really know what their intended purpose is/was, but I use a preload event to update persistent variables when a save is loaded. So to use my music player add-on as an example: It can (as of 1.13.something) be used in MP/SP/campaigns since it's a modification, and things like the playlists/what playlist or song to play on loading/etc are saved to a persistent variable file. However, since this data is stored separately from a particular save file, it can change outside of that save file. So, for example, (1) a user starts a campaign and creates 1 playlist, (2) plays an MP match during which they create another playlist, (3) then they come back to the campaign. In that situation, I use a preload event to update the persistent variables so that in (3), they have the playlist they created in (2).
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code

fabi
Developer
Posts: 1223
Joined: March 21st, 2004, 2:42 pm
Location: Germany

Re: Irdya - Wesmere Reference Implementation

Post by fabi » April 17th, 2016, 6:17 pm

Pentarctagon wrote:Does that mean variables can be declared just about anywhere?
Not quite.
It means Lua/MoonScript can be coded anywhere.
Declaring variables is only one of the options.

Let's have another example to show what is possible.

Code: Select all

last = 10
for i=1, last
    scenario
        id: "scenario_number_#{i}"
        next_scenario: i  != last and "scenario_number_#{i + 1}" or nil
        side:
            side:1
            controller: "human"
            ...
        side:
            side:2
            gold: 150 + 50 * i
            controller: "ai"
        ...
This code will define 10 scenarios with a linear connection between them.
With each successive scenario the ai enemy gets 50 pieces more gold.
You can also define your own helper functions.
As for preload events, I don't really know what their intended purpose is/was, but I use a preload event to update persistent variables when a save is loaded. So to use my music player add-on as an example: It can (as of 1.13.something) be used in MP/SP/campaigns since it's a modification, and things like the playlists/what playlist or song to play on loading/etc are saved to a persistent variable file. However, since this data is stored separately from a particular save file, it can change outside of that save file. So, for example, (1) a user starts a campaign and creates 1 playlist, (2) plays an MP match during which they create another playlist, (3) then they come back to the campaign. In that situation, I use a preload event to update the persistent variables so that in (3), they have the playlist they created in (2).
I see.
This example shows me why keeping the preload event is necessary.
Thank you very much.
"Wesnoth has many strong points but team and users management are certainly not in them." -- pyrophorus

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

Re: Irdya - Wesmere Reference Implementation

Post by Pentarctagon » April 17th, 2016, 6:37 pm

Huh, neat.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code

fabi
Developer
Posts: 1223
Joined: March 21st, 2004, 2:42 pm
Location: Germany

Re: Irdya - Wesmere Reference Implementation

Post by fabi » April 21st, 2016, 1:06 am

Okay, I have learned that I haven't communicated well enough how WesMods and WSL works.

Let me try again.

Irdya reads all its content in the form of WesMods.
After loading a few of them finally a scenario is started.

Irdya can't do much more.
Load WesMods and play scenarios.

When you have a host that runs Irdya it manages the communication to the clients.
Those are either human players interacting with a Wesmere display client or artificial intelligences.

Loading a WesMod means that every .lua and .moon script file beyond the parent directory is executed.
During the execution of a script it can call and use only variables and functions of the environment it is executed in.

This is used to sandbox WesMods in case a hostile modder wants to format your drive or spy your credit card number.
But it although allows for separating namespaces properly.

Toplevel WML tags usually transform into those environments.
But there are exceptions.

The [units] toplevel tag is a good example:
Irdya executes every script below a folder (in the toplevel of a loaded WesMod) called "Units" in an environment which features the "unit_type", "move_type", "race" and "trait" handler functions.
Note that those have been subtags of [units] in WML.
The WSL designer does not have to bother with file inclusion syntax.
It is enough to drop the file into the right directory.

Whenever you define a global variable (or function) in one of the files this global is available during later file executions.
I use this mechanism to export every unit related macro translated as Lua function/variable into the "Units" environment.

MoonScript supports syntactic sugar for doing so:

Code: Select all

export ^

GENERIC_NO_TRAIT_UNIT = (some, arguments) ->
    ...
    ...

...
"export ^" is doing the export for every capitalized definition after it.
This comes in handy since Wesnoth macros are all upper case.

So the purpose of the scripts is to execute regular Lua/MoonScript code.
But the only action that can define game content is using the WSL handler functions which are valid in the current environment.
Note that every Add-on can define new WSL handler functions.
(Please also note that WSL handler functions are not the same as WSL Action functions, which can also defined by each Add-on.)

Thus you can have all kind of complex coding to produce the tables used as argument for the handler functions,
in every and each content/config file.
"Wesnoth has many strong points but team and users management are certainly not in them." -- pyrophorus

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

Re: Irdya - Wesmere Reference Implementation

Post by Pentarctagon » April 23rd, 2016, 3:13 pm

So, if I'm understanding this correctly, if I declare a non-global function foo() in the folder AddOn1/Test1, then that function would not be available to Irdya once it starts reading the folder AddOn1/Test2? Or AddOn2/Test3? And the same is true for any non-global variable?

Also, I'm not sure if I asked this before here or for the regular Wesnoth lua implementation, but since there's no preprocessing/file inclusion, is there a way to split up a single event or the contents of a tag across multiple files? To (again) use my music player add-on as an example, the WML for the menu is split up among a bunch of files, since having everything in a single file would be ~5500 lines long. I would imagine that some of the more complex survival scenarios are whatnot would do a similar thing.

Also also, as a side note, all mainline Wesnoth macros are uppercase, but the preprocessor does not require that they be so. It is possible to declare a macro as all lowercase or mixed-case, if someone wanted to for whatever reason.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code

fabi
Developer
Posts: 1223
Joined: March 21st, 2004, 2:42 pm
Location: Germany

Re: Irdya - Wesmere Reference Implementation

Post by fabi » April 25th, 2016, 8:06 am

Pentarctagon wrote:So, if I'm understanding this correctly, if I declare a non-global function foo() in the folder AddOn1/Test1, then that function would not be available to Irdya once it starts reading the folder AddOn1/Test2? Or AddOn2/Test3? And the same is true for any non-global variable?
Well, Irdya would not read anything below Test2 in your add-on if you do not introduce a Test2 namespace in it. (or in a WesMod that is earlier loaded)

If we assume that "Test*" are defined namespaces then your statement holds.
Lua uses lexical scoping and Irdya does not change that.
So there is nothing special about how local variables work.
Also, I'm not sure if I asked this before here or for the regular Wesnoth lua implementation, but since there's no preprocessing/file inclusion, is there a way to split up a single event or the contents of a tag across multiple files?
Wesnoth makes use of Lua's "require" function.
It can be used to read files and and assign their return to global or local variables.
This mechanism is usually used in Lua to split your codebase into modules.

While relying on require heavily for internal matters, Irdya does not export this or a similar function into any of the WesMod or ActionWSL contexts.
So you use global variables for that matter.
To (again) use my music player add-on as an example, the WML for the menu is split up among a bunch of files, since having everything in a single file would be ~5500 lines long.
Yeah, when I was still young and beautiful, everything above around 800 line of code was considered to be a candidate for file splitting.
No matter if your code makes use of require or relies on globals, the trick is to split functionality into more functions, tables into subtables.
There is not a single way of doing those stuff.
Let's try some examples.
I would imagine that some of the more complex survival scenarios are whatnot would do a similar thing.
On a side note, I think a similar concept to [unit_type]'s base unit concept also suits scenarios.
So Irdya's scenarios will allow to specify a parent scenario whose attributes are imported and can then be extended or overwritten in the child scenario.
Complex scenarios can use this sort of mechanism to split functionality over several files.

Another easy to spot action to split scenario code into more files would be to just take the command functions of related events into a file for each concern.
In those files local helper variables/functions can then help to avoid duplicate code.

You can also just export a variable containing the table that will later be the argument to the scenario handler function.
Then every of your files just manipulates that table via the global variable until it is ready and finally scenario is called.

Keep in mind, everything in Lua can be put into a table so you do not need to spoil the global namespace with more than a single variable if you don't feel like having a lot globals.
Let's say your table's variable is called "pentarctagon_music_player", to get sure that a naming conflict is not very likely.
Having to write pentarctagon_music_player.something_maybe_long_as_well can be tedious.
So MoonScript offers syntactic sugar:
import pentacrtagon_music_player
something_maybe_long_as_well("foo", 5)
something_shorter = 8
...
Import just creates a local variable for every child (better: key) of the table it is applied onto.
Also also, as a side note, all mainline Wesnoth macros are uppercase, but the preprocessor does not require that they be so. It is possible to declare a macro as all lowercase or mixed-case, if someone wanted to for whatever reason.
Yes, same as with the Lua functions they are transferred into.
So in both worlds the naming scheme is only a coding convention.

The export of upper case objects into the global namespace of the current environment is not an automatism but supported by additional syntactic sugar MoonScripts provides.
"Wesnoth has many strong points but team and users management are certainly not in them." -- pyrophorus

fabi
Developer
Posts: 1223
Joined: March 21st, 2004, 2:42 pm
Location: Germany

Re: Irdya - Wesmere Reference Implementation

Post by fabi » April 26th, 2016, 9:24 pm

Pentarctagon wrote:So, if I'm understanding this correctly, if I declare a non-global function foo() in the folder AddOn1/Test1, then that function would not be available to Irdya once it starts reading the folder AddOn1/Test2? Or AddOn2/Test3? And the same is true for any non-global variable?
Sorry, let's try that again.
Should have read your question more carefully.

Non-global functions, or in general all local variables (no matter if that variable stores a nil, boolean, number, string, function, userdata, thread or table value), have a lifespan that ends when the execution reaches the end of a block.

The bodies of do, while, repeat, if, for and function are blocks.
Additional, the whole content of a file is evaluated as a block (called chunk in that case).

Thus, the longest lifespan a local variable can have is when it is declared at a file's toplevel.
But it always drops out of visibility when the file is finished evaluating.

So, you need always global variables if their concern is spread over several files, no matter if they are in the same namespace or not.

If your variable is to be shared by multiple namespaces then you need to export it at the toplevel of a WesMod.
Global variables defined there are exported into every environment.
"Wesnoth has many strong points but team and users management are certainly not in them." -- pyrophorus

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

Re: Irdya - Wesmere Reference Implementation

Post by Pentarctagon » April 28th, 2016, 8:21 am

I think I understand, but at this point it would probably just be simpler for me to wait and play around with this at some point :lol:
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code

Post Reply