Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the game event system to be based on Lua at the core #5663

Merged
merged 22 commits into from Jul 19, 2022

Conversation

CelticMinstrel
Copy link
Member

@CelticMinstrel CelticMinstrel commented Apr 4, 2021

All events are now just a Lua function and a package of arguments that are passed to the function. A typical event added via WML (ie, with the [event] tag) is the function wesnoth.wml_actions.command with the contained ActionWML tags passed as the argument, so they work just the same as before. However, you can now add events in two other ways:

  • Instead of using ActionWML, you can write the entire event inline as Lua code using [event]code=. Although this is similar to just using an event containing a single [lua] tag, there are some differences. The code is compiled when the event is added, rather than when it is executed, and the argument passed to the event code is a copy of the [event] tag with filter data and event name and ID stripped out.
  • You can now register an event directly from Lua using the new wesnoth.game_events.add function, which supercedes the on_event() system that World Conquest and a few other things depend on. Unlike on_event(), this interface supports everything that [event] does, such as first_time_only=true or giving the event an ID that will allow other events to remove it. It also supports some things that [event] doesn't, such as using an arbitrary Lua function to handle the event (although if you do this, the event becomes unserializable, just the same as if you used on_event()) or marking the event as a menu item event (meaning it will be removed if the menu item with the same ID is removed).

The other significant change in this PR is a refactor of the event filtering system, which would make it very easy to add a new type of filter if we wanted to in the future (although I'm not anticipating any new types). As part of that, two new ways of filtering in events have been added:

  • The filter_formula key in [event] takes a WFL formula that determines whether the event should trigger. It can access all the event context info (like loc1, event_id, unit1, etc) as well as the game state (such as map, units, turn, and time_of_day). In particular, it exposes event context info that nothing else does in event_data, although there may not be any way to actually set that data yet in [fire_event].
  • The filter key in [event] takes Lua code that determines whether the event should trigger. If there is a [filter_args] tag, its contents is passed to this function.
  • In addition, when adding an event from Lua, you can pass an arbitrary Lua function as the filter. Doing this makes the event unserializable, of course.

One other thing I've done here is to divorce menu items from events at the Lua level. This was already the case in C++, and it seemed to make for a cleaner API. The relevant functions were never documented, so this is probably a minor thing, but basically: wesnoth.interface.set_menu_item adds or updates a menu item but does not make it do anything - the [command] tag is ignored. To make it do something, you need to use wesnoth.game_events.add to create the event that the menu item will trigger. Of course, [set_menu_item] still does both for you.

@github-actions github-actions bot added AI Issues with the AI engine, including micro AIs. Lua API Issues with the Lua engine and API. UI User interface issues, including both back-end and front-end issues. Units Issues that involve unit definitions or their implementation in the engine. WFL Issues involving the Wesnoth Formula Language engine and APIs. labels Apr 4, 2021
@Pentarctagon
Copy link
Member

Unit tests proving out the different aspects of this functionality would be very beneficial.

@Pentarctagon
Copy link
Member

Adding doxygen doc comments to methods is also a good habit for us to all get into, I think.

data/lua/wml-tags.lua Outdated Show resolved Hide resolved
@github-actions github-actions bot added Building Build-time issues. macOS OS-specific issues that apply to Apple macOS. Unit Tests Issues involving Wesnoth's unit test suite. labels Apr 11, 2021
@CelticMinstrel
Copy link
Member Author

CelticMinstrel commented Apr 11, 2021

I think this addresses most of the concerns people mentioned. I still have a few things to finish though:

  • delayed_variable_substitution=yes seems to be broken
  • [remove_event] seems to be broken
  • make pending_event_handler moveable
  • extract the code chunk name fix

Copy link
Contributor

@stevecotton stevecotton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There still isn't enough documentation in this PR to enable the PR to be reviewed.

Change requested: add the documentation.

@CelticMinstrel
Copy link
Member Author

The documentation goes on the wiki though, right? It's not part of the PR.

@stevecotton
Copy link
Contributor

There's more than just API docs to add. I think docs should be written like the game Taboo - try to explain what it does without repeating the words in the class name, function name, argument types or argument names; that often acts as a design review.

The gamestate_callable class could do with an explanation of what it is, and that it doesn't need any state passed to the constructor.

The event_callable and pending_event_handler classes could do with docs too, so could event_filter.

@CelticMinstrel
Copy link
Member Author

Does that help?

@CelticMinstrel
Copy link
Member Author

I drafted up some documentation for the Lua API on the wiki.

I realize it's perhaps a little tucked away in this PR, but does anyone have any comments on the Lua unit_test API that I've added here?

@stevecotton
Copy link
Contributor

I realize it's perhaps a little tucked away in this PR, but does anyone have any comments on the Lua unit_test API that I've added here?

I'll do a review this evening, but was going to ask if you'd split this into a separate PR.

Unlike the old wesnoth.game_events.on_event hook and the "convenient" on_event() wrapper for it, this new functionality supports all of the features of WML events, with the sole exception of serialization, since it's not possible to reliably serialize a Lua function.

This commit also divorces menu items from the event that they trigger. The undocumented wesnoth.interface.set_menu_item function no longer adds an event for the menu item; the caller needs to separately register an event using the new functionality.
* These functions take the full event data config as the final argument, rather than just the weapon info subconfigs.
* The [fire_event] tag now supports a [data] tag that can add additional data to the event, for example damage_inflicted. The [primary_attack]  and [secondary_attack] tags are still supported and are not deprecated.
* wesnoth.current.event_context now has a data child which holds the full event data. It still duplicates common info (weapons and damage inflicted) in the same way as before.
- Don't try to serialize an event with a Lua filter (ie, add{filter = function() end})
- Write the serialization warning to in-game chat, but ONLY if the event was registered after preload
… a repeating event

This is a somewhat controversial change!

PROS:
- This makes wesnoth.game_events.add a drop-in replacement for the on_event function
- If you're registering events in preload, most of them WILL be repeating events

CONS:
- This makes the default depend on the call style; in positional style, it defaults to repeating, and in named-argument style, it defaults to non-repeating
- This makes the default different from the WML default of non-repeating events
Basically this means each of the call modes of the old function is now a separate function.

- add_repeating and add_menu take an ID and a function
- add_wml takes variable substitution setting and a config
- add takes the full options table
Since they're non-serializable, the code can't be shown, but the fact that unspecified Lua code is present will be shown.
These are taken as synonyms of the actual internal tag names, [first] and [second]. So, first is interchangeable with primary_attack and second is interchangeable with secondary_attack.
Although it's already possible to pass {formula = "whatever"},
this change allows mixing that with the simplified syntax,
such as {formula = "whatever", side = {side = 3}}
This creates a filter that's read dynamically from the specified WML variable.
- Add default name for wesnoth.game_events.add when it's a menu item
- Add error message when both ID and name are empty
@CelticMinstrel CelticMinstrel merged commit 5001999 into master Jul 19, 2022
stevecotton added a commit to stevecotton/wesnoth that referenced this pull request Nov 16, 2022
Fixes wesnoth#6898. The issue is that non-WML events added through the new events API
always disable undo with no equivalent of WML's `[allow_undo]`. The long-term
fix is to add a way to do that; however until that's available then listeners
for `moveto` need to use the old `on_event` API. The old `on_event` API can't
be deprecated yet, and this is enforced by our unit tests (the build fails if
there are unexpected deprecation warnings during the tests).

Reverts most of 7e234f8. Does not revert files
that only listen for non-undoable events such as `die` or `new turn`.

Reverts the deprecation part of wesnoth#5663's 8cd1332.
stevecotton added a commit to stevecotton/wesnoth that referenced this pull request Nov 16, 2022
Fixes wesnoth#6898. The issue is that non-WML events added through the new events API
always disable undo with no equivalent of WML's `[allow_undo]`. The long-term
fix is to add a way to do that; however until that's available then listeners
for `moveto` need to use the old `on_event` API. The old `on_event` API can't
be deprecated yet, and this is enforced by our unit tests (the build fails if
there are unexpected deprecation warnings during the tests).

Reverts most of 7e234f8. Does not revert files
that only listen for non-undoable events such as `die` or `new turn`.

Reverts the deprecation part of wesnoth#5663's 8cd1332.
stevecotton added a commit that referenced this pull request Nov 19, 2022
Fixes #6898. The issue is that non-WML events added through the new events API
always disable undo with no equivalent of WML's `[allow_undo]`. The long-term
fix is to add a way to do that; however until that's available then listeners
for `moveto` need to use the old `on_event` API. The old `on_event` API can't
be deprecated yet, and this is enforced by our unit tests (the build fails if
there are unexpected deprecation warnings during the tests).

Reverts most of 7e234f8. Does not revert files
that only listen for non-undoable events such as `die` or `new turn`.

Reverts the deprecation part of #5663's 8cd1332.
bencsikandrei pushed a commit to bencsikandrei/wesnoth that referenced this pull request Nov 21, 2022
Fixes wesnoth#6898. The issue is that non-WML events added through the new events API
always disable undo with no equivalent of WML's `[allow_undo]`. The long-term
fix is to add a way to do that; however until that's available then listeners
for `moveto` need to use the old `on_event` API. The old `on_event` API can't
be deprecated yet, and this is enforced by our unit tests (the build fails if
there are unexpected deprecation warnings during the tests).

Reverts most of 7e234f8. Does not revert files
that only listen for non-undoable events such as `die` or `new turn`.

Reverts the deprecation part of wesnoth#5663's 8cd1332.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AI Issues with the AI engine, including micro AIs. Building Build-time issues. Campaign (any) Deprecated tag, replaced with separate tags for each mainline campaign Lua API Issues with the Lua engine and API. macOS OS-specific issues that apply to Apple macOS. MP Issues with multiplayer support or bundled multiplayer content. Schema UI User interface issues, including both back-end and front-end issues. Unit Tests Issues involving Wesnoth's unit test suite. Units Issues that involve unit definitions or their implementation in the engine. WFL Issues involving the Wesnoth Formula Language engine and APIs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants