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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
30dec56
Events are now a Lua function instead of WML
CelticMinstrel Apr 2, 2021
eb2d93f
Enable setting an arbitrary Lua function as an event handler.
CelticMinstrel Apr 4, 2021
34c2810
Add [event]filter_formula= for WFL event filtering
CelticMinstrel Apr 4, 2021
2e13265
Support passing an arbitrary Lua function as the filter when the even…
CelticMinstrel Apr 4, 2021
82ff54d
Move the event firing functions to wesnoth.game_events
CelticMinstrel Apr 4, 2021
5c1558e
Improve the handling of event serialization when Lua code is attached
CelticMinstrel Apr 11, 2021
ee19d82
Adding an event handler via the positional call style now defaults to…
CelticMinstrel Apr 11, 2021
4ac7611
Unit tests for each way of assigning an action to an event handler
CelticMinstrel Apr 11, 2021
74f0b9e
Unit tests for the new filter options
CelticMinstrel Apr 11, 2021
c12959d
Update [remove_event] to use new API
CelticMinstrel Apr 14, 2021
59ee644
Update schema for the new [event] options
CelticMinstrel Apr 15, 2021
5f1d7dd
Fix dynamic filters behaviour change
CelticMinstrel May 22, 2022
9eca255
Split wesnoth.game_events.add into multiple functions
CelticMinstrel Jun 21, 2022
0eef9b8
Include non-serializable events in the gamestate inspector
CelticMinstrel Jun 22, 2022
e7579d6
Fix non-serializable events being serialized as an empty [event] tag
CelticMinstrel Jun 22, 2022
3441e56
Add luadoc for the new event functions
CelticMinstrel Jun 22, 2022
b1e894d
Support primary_attack and secondary_attack in wesnoth.game_events.fire
CelticMinstrel Jun 22, 2022
6a764c4
Replace deprecated usages of on_event()
CelticMinstrel Jun 22, 2022
c5098e1
Fix WML errors showing as Lua errors
CelticMinstrel Jun 24, 2022
0ec27c2
Support "formula" in the filter table
CelticMinstrel Jun 28, 2022
d0d9b00
Support {filter_type = "variable_path"}
CelticMinstrel Jun 28, 2022
1edd0cb
Some cleanup of the events API
CelticMinstrel Jul 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion data/campaigns/World_Conquest/lua/campaign_main.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- the main file for the WC2 mp campaign

T = wml.tag
on_event = wesnoth.require("on_event")
on_event = wesnoth.game_events.add_repeating


wesnoth.dofile("./game_mechanics/_load.lua")
Expand Down
38 changes: 36 additions & 2 deletions data/lua/core/interface.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,41 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
wesnoth.print = wesnoth.deprecate_api('wesnoth.print', 'wesnoth.interface.add_overlay_text', 1, nil, function(cfg)
wesnoth.wml_actions.print(cfg)
end)
-- No deprecation for these since since they're not actually public API yet
wesnoth.set_menu_item = wesnoth.interface.set_menu_item
wesnoth.set_menu_item = wesnoth.deprecate_api('wesnoth.set_menu_item', 'wesnoth.interface.set_menu_item', 1, nil, function(id, cfg)
-- wesnoth.set_menu_item added both the menu item and the event that it triggers
-- wesnoth.interface.set_menu_item only adds the menu item
wesnoth.interface.set_menu_item(id, cfg)
wesnoth.game_events.add_menu(cfg.id, wesnoth.wml_actions.command)
end)
wesnoth.clear_menu_item = wesnoth.interface.clear_menu_item
-- Event handlers don't have a separate module Lua file so dump those here
wesnoth.add_event_handler = wesnoth.deprecate_api('wesnoth.add_event_hander', 'wesnoth.game_events.add', 1, nil, function(cfg) wesnoth.wml_actions.event(cfg) end)
wesnoth.remove_event_handler = wesnoth.deprecate_api('wesnoth.remove_event_handler', 'wesnoth.game_events.remove', 1, nil, wesnoth.game_events.remove)

local function old_fire_event(fcn)
return function(...)
local id = select(1, ...)
local loc1, n1 = wesnoth.map.read_location(select(2, ...))
local loc2, n2 = wesnoth.map.read_location(select(2 + n1, ...))
local weap1, weap2 = select(2 + n1 + n2)
local data = {}
if weap1 ~= nil then
table.insert(data, wml.tag.first(weap1))
end
if weap2 ~= nil then
table.insert(data, wml.tag.second(weap2))
end
if n1 > 0 then
if n2 > 0 then
fcn(id, loc1, loc2, data)
else
fcn(id, loc1, data)
end
else
fcn(id, data)
end
end
end
wesnoth.fire_event = wesnoth.deprecate_api('wesnoth.fire_event', 'wesnoth.game_events.fire', 1, nil, old_fire_event(wesnoth.game_events.fire))
wesnoth.fire_event_by_id = wesnoth.deprecate_api('wesnoth.fire_event_by_id', 'wesnoth.game_events.fire_by_id', 1, nil, old_fire_event(wesnoth.game_events.fire_by_id))
end
3 changes: 1 addition & 2 deletions data/lua/diversion.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

local _ = wesnoth.textdomain 'wesnoth-help'
local T = wml.tag
local on_event = wesnoth.require("on_event")

local u_pos_filter = function(u_id)

Expand Down Expand Up @@ -100,7 +99,7 @@ function wesnoth.wml_actions.on_undo_diversion(cfg)
status_anim_update(true)
end

on_event("moveto, die, recruit, recall", function()
wesnoth.game_events.add_repeating("moveto, die, recruit, recall", function()
status_anim_update()

end)
Expand Down
3 changes: 1 addition & 2 deletions data/lua/feeding.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

local _ = wesnoth.textdomain 'wesnoth-help'
local T = wml.tag
local on_event = wesnoth.require("on_event")

-- The feeding event code
on_event("die", function()
wesnoth.game_events.add_repeating("die", function()
local ec = wesnoth.current.event_context

if not ec.x1 or not ec.y1 or not ec.x2 or not ec.y2 then
Expand Down
4 changes: 2 additions & 2 deletions data/lua/on_event.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ local function on_event(eventname, priority, fcn)
end
end

core_on_event = on_event
return on_event
core_on_event = wesnoth.deprecate_api("on_event", "wesnoth.game_events.add_repeating", 1, nil, on_event)
return core_on_event
13 changes: 8 additions & 5 deletions data/lua/wml-tags.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,12 @@ function wml_actions.fire_event(cfg)

local w1 = wml.get_child(cfg, "primary_attack")
local w2 = wml.get_child(cfg, "secondary_attack")
if w2 then w1 = w1 or {} end
local data = wml.get_child(cfg, "data") or {}
if w1 then table.insert(data, wml.tag.first(w1)) end
if w2 then table.insert(data, wml.tag.second(w2)) end

if cfg.id and cfg.id ~= "" then wesnoth.fire_event_by_id(cfg.id, x1, y1, x2, y2, w1, w2)
elseif cfg.name and cfg.name ~= "" then wesnoth.fire_event(cfg.name, x1, y1, x2, y2, w1, w2)
if cfg.id and cfg.id ~= "" then wesnoth.game_events.fire_by_id(cfg.id, x1, y1, x2, y2, data)
elseif cfg.name and cfg.name ~= "" then wesnoth.game_events.fire(cfg.name, x1, y1, x2, y2, data)
end
end

Expand Down Expand Up @@ -663,6 +665,7 @@ end

function wml_actions.set_menu_item(cfg)
wesnoth.interface.set_menu_item(cfg.id, cfg)
wesnoth.game_events.add_menu(cfg.id, wml_actions.command)
end

function wml_actions.place_shroud(cfg)
Expand Down Expand Up @@ -727,15 +730,15 @@ function wml_actions.event(cfg)
wesnoth.deprecated_message("[event]remove=yes", 2, "1.17.0", "Use [remove_event] instead of [event]remove=yes")
wml_actions.remove_event(cfg)
else
wesnoth.add_event_handler(cfg)
wesnoth.game_events.add_wml(cfg)
end
end

function wml_actions.remove_event(cfg)
local id = cfg.id or wml.error("[remove_event] missing required id= key")

for _,w in ipairs(id:split()) do
wesnoth.remove_event_handler(w)
wesnoth.game_events.remove(w)
end
end

Expand Down
2 changes: 1 addition & 1 deletion data/modifications/pick_advance/main.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-- << pick_advance/main.lua

local on_event = wesnoth.require "on_event"
local on_event = wesnoth.game_events.add_repeating
local F = wesnoth.require "functional"
local T = wml.tag
local _ = wesnoth.textdomain "wesnoth"
Expand Down
2 changes: 1 addition & 1 deletion data/multiplayer/scenarios/2p_Dark_Forecast.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

local _ = wesnoth.textdomain 'wesnoth-multiplayer'
local T = wml.tag
local on_event = wesnoth.require("on_event")
local on_event = wesnoth.game_events.add_repeating

local random_spawns = {
{
Expand Down
2 changes: 1 addition & 1 deletion data/multiplayer/scenarios/2p_Isle_of_Mists.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local _ = wesnoth.textdomain 'wesnoth-multiplayer'
local T = wml.tag
local on_event = wesnoth.require("on_event")
local on_event = wesnoth.game_events.add_repeating

local random_spawns = {
{
Expand Down
1 change: 1 addition & 0 deletions data/schema/core/addons.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
super="$action_wml"
{SIMPLE_KEY name string}
{SIMPLE_KEY id string}
{SIMPLE_KEY filter_formula string}
{DEFAULT_KEY first_time_only bool yes}
{DEFAULT_KEY delayed_variable_substitution bool no}

Expand Down
99 changes: 99 additions & 0 deletions data/test/scenarios/events-test_actions.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@

# This is kinda a duplicate of a basic unit test system sanity test, but... it seems to fit here as well...
{GENERIC_UNIT_TEST "event_test_action_wml" (
[event]
name=start
{SUCCEED}
[/event]
)}

# Test that dynamically adding an event from Lua works
# There's two different ways of adding events, so test both
Copy link
Contributor

Choose a reason for hiding this comment

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

I acknowledge these were written before @Pentarctagon's new style for test comments, but please update the test files to the API(s) being tested: style.

A # wmllint: no translatables would be good too.

{GENERIC_UNIT_TEST "event_test_lua" (
[event]
name=preload
[lua]
code=<<
wesnoth.game_events.add_repeating('new turn', function()
unit_test.succeed()
end)
>>
[/lua]
[/event]
)}
{GENERIC_UNIT_TEST "event_test_lua_advanced" (
[event]
name=preload
[lua]
code=<<
wesnoth.game_events.add{
name = 'new turn',
action = function()
unit_test.succeed()
end
}
>>
[/lua]
[/event]
)}

# Test that first_time_only works correctly in Lua events
{GENERIC_UNIT_TEST "event_test_lua_repeat" (
[event]
name=preload
[lua]
code=<<
wml.variables.only_once = 0
wml.variables.should_repeat = 0
wesnoth.game_events.add{
name = 'new turn',
first_time_only = true,
action = function()
wml.variables.only_once = wml.variables.only_once + 1
end
}
wesnoth.game_events.add{
name = 'new turn',
first_time_only = false,
action = function()
wml.variables.should_repeat = wml.variables.should_repeat + 1
end
}
>>
[/lua]
[/event]
[event]
name=side 1 turn 1
[end_turn][/end_turn]
[/event]
[event]
name=side 2 turn 1
[end_turn][/end_turn]
[/event]
[event]
name=side 1 turn 2
[end_turn][/end_turn]
[/event]
[event]
name=side 2 turn 2
{ASSERT ({VARIABLE_CONDITIONAL only_once equals 1})}
{ASSERT ({VARIABLE_CONDITIONAL should_repeat equals 2})}
{SUCCEED}
[/event]
)}

# Verify that a warning is produced if adding an event that would break saved games
{GENERIC_UNIT_TEST "event_test_lua_break_save" (
[event]
name=start
[lua]
code=<<
wesnoth.game_events.add{
name = 'new turn',
action = function() end
}
unit_test.succeed()
>>
[/lua]
[/event]
)}
116 changes: 116 additions & 0 deletions data/test/scenarios/events-test_filters.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,119 @@
{RETURN ({VARIABLE_CONDITIONAL triggers equals 4})}
[/event]
)}

{GENERIC_UNIT_TEST event_test_filter_wfl (
[event]
name=start
{VARIABLE triggers 0}
[/event]
[event]
name=side turn
first_time_only=no
filter_formula="turn_number = side_number"
{VARIABLE_OP triggers add 1}
{ASSERT ({VARIABLE_CONDITIONAL side_number equals $turn_number})}
[/event]
[event]
name=turn 3
{RETURN ({VARIABLE_CONDITIONAL triggers equals 2})}
[/event]
[event]
name=side turn
first_time_only=no
[end_turn][/end_turn]
[/event]
)}

{GENERIC_UNIT_TEST event_test_filter_wfl2 (
[event]
name=start
{VARIABLE triggers 0}
[do_command]
[move]
x=7,7,6,5,4,3,3,3
y=3,4,4,5,4,4,3,2
[/move]
[/do_command]
{RETURN ({VARIABLE_CONDITIONAL triggers equals 3})}
[/event]
[event]
name=enter hex
first_time_only=no
filter_formula="loc.x = loc.y"
{VARIABLE_OP triggers add 1}
[/event]
)}

{GENERIC_UNIT_TEST event_test_filter_lua_serializable (
[event]
name=start
{VARIABLE triggers 0}
[/event]
[event]
name=side turn
first_time_only=no
[filter_condition]
[lua]
code=<<return wesnoth.current.turn == wesnoth.current.side>>
[/lua]
[/filter_condition]
{VARIABLE_OP triggers add 1}
{ASSERT ({VARIABLE_CONDITIONAL side_number equals $turn_number})}
[/event]
[event]
name=turn 3
{RETURN ({VARIABLE_CONDITIONAL triggers equals 2})}
[/event]
[event]
name=side turn
first_time_only=no
[end_turn][/end_turn]
[/event]
)}

{GENERIC_UNIT_TEST event_test_filter_lua_dynamic (
[event]
name=preload
[lua]
code=<<
wml.variables.triggers = 0
stevecotton marked this conversation as resolved.
Show resolved Hide resolved
wesnoth.game_events.add{
name = 'side turn',
first_time_only = false,
filter = function()
return wesnoth.current.turn == wesnoth.current.side
end,
action = function()
wml.variables.triggers = wml.variables.triggers + 1
unit_test.assert_equal(wesnoth.current.turn, wesnoth.current.side, 'filter correctly passed')
end
}
>>
[/lua]
[/event]
[event]
name=side 2 turn 3
{RETURN ({VARIABLE_CONDITIONAL triggers equals 2})}
[/event]
[event]
name=side turn
first_time_only=no
[end_turn][/end_turn]
[/event]
)}

{GENERIC_UNIT_TEST event_test_filter_lua_dynamic_break_save (
[event]
name=start
[lua]
code=<<
wesnoth.game_events.add{
name = 'new turn',
filter = function() end
}
unit_test.succeed()
>>
[/lua]
[/event]
)}