The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
lua_attributes.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2009 - 2025
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13*/
14
15/// Attribute registration system, mainly for objects with a lot of attributes, like units
16/// Not used for GUI2 widgets, as they're even more complicated with a deep hierarchy.
17
18#pragma once
19
20struct lua_State;
21class t_string;
22class vconfig;
23
24#include "config.hpp"
25#include "map/location.hpp"
26#include "variable_info.hpp"
27
28#include <string>
29#include <string_view>
30#include <vector>
31
32template<typename T>
33std::decay_t<T> lua_check(lua_State *L, int n);
34
35/// Holds a lookup table for members of one type of object.
37 inline static std::map<std::string_view /* metatable */, std::reference_wrapper<luaW_Registry>> lookup;
38 using getters_list = std::map<std::string /* attribute */, std::function<bool(lua_State* L,bool nop)>>;
39 /// A map of callbacks that read data from the object.
41 using setters_list = std::map<std::string, std::function<bool(lua_State* L,int idx,bool nop)>>;
42 /// A map of callbacks that write data to the object.
44 using validators_list = std::map<std::string, std::function<bool(lua_State* L)>>;
45 /// A map of callbacks that check if a member is available.
47 /// The internal metatable string for the object (from __metatable)
48 std::string private_metatable;
49 /// Optional external metatable for the object (eg "wesnoth", "units")
50 /// All entries of this table will be treated as members of the object.
51 std::vector<std::string> public_metatable;
52 luaW_Registry() = delete;
53 luaW_Registry(const std::initializer_list<std::string>& mt);
55 /// Implement __index metamethod
56 int get(lua_State* L);
57 /// Implement __newindex metamethod
58 int set(lua_State* L);
59 /// Implement __dir metamethod
60 int dir(lua_State* L);
61};
62
64
65template<typename object_type, typename value_type>
67{
68 virtual value_type get(lua_State* L, const object_type& obj) const = 0;
69 virtual ~lua_getter() = default;
70};
71
72template<typename object_type, typename value_type>
74{
75 virtual void set(lua_State* L, object_type& obj, const value_type& value) const = 0;
76 virtual ~lua_setter() = default;
77};
78
79template<typename object_type>
81{
82 virtual bool is_active(lua_State* L, const object_type& obj) const = 0;
83 virtual ~lua_validator() = default;
84};
85
86template<typename T> struct lua_object_traits;
87
88template<typename object_type, typename value_type, typename action_type, lua_attrfunc_type type>
89void register_lua_attribute(const char* name)
90{
91 using obj_traits = lua_object_traits<object_type>;
92 using map_type = std::conditional_t<type == lua_attrfunc_type::validator, luaW_Registry::validators_list, std::conditional_t<type == lua_attrfunc_type::setter, luaW_Registry::setters_list, luaW_Registry::getters_list>>;
93 using callback_type = typename map_type::mapped_type;
94 map_type* map;
95 callback_type fcn;
96 if constexpr(type == lua_attrfunc_type::setter) {
97 map = &luaW_Registry::lookup.at(obj_traits::metatable).get().setters;
98 fcn = [action = action_type()](lua_State* L, int idx, bool nop) {
99 if(nop) return true;
100 decltype(auto) obj = obj_traits::get(L, 1);
101 action.set(L, obj, lua_check<value_type>(L, idx));
102 return true;
103 };
104 } else if constexpr(type == lua_attrfunc_type::getter) {
105 map = &luaW_Registry::lookup.at(obj_traits::metatable).get().getters;
106 fcn = [action = action_type()](lua_State* L, bool nop) {
107 if(nop) return true;
108 lua_push(L, action.get(L, obj_traits::get(L, 1)));
109 return true;
110 };
111 } else if constexpr(type == lua_attrfunc_type::validator) {
112 map = &luaW_Registry::lookup.at(obj_traits::metatable).get().validators;
113 fcn = [action = action_type()](lua_State* L) {
114 return action.is_active(L, obj_traits::get(L, 1));
115 };
116 }
117 (*map)[std::string(name)] = fcn;
118}
119
120#define LATTR_MAKE_UNIQUE_ID(base, id, obj_name) BOOST_PP_CAT(BOOST_PP_CAT(base, id), BOOST_PP_CAT(_for_, obj_name))
121
122#define LATTR_GETTER5(name, value_type, obj_type, obj_name, id) \
123struct LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name) : public lua_getter<obj_type, value_type> { \
124 using object_type = obj_type; \
125 virtual value_type get(lua_State* L, const object_type& obj_name) const override; \
126}; \
127struct LATTR_MAKE_UNIQUE_ID(getter_adder_, id, obj_name) { \
128 LATTR_MAKE_UNIQUE_ID(getter_adder_, id, obj_name) () \
129 { \
130 register_lua_attribute<obj_type, value_type, LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name), lua_attrfunc_type::getter>(name); \
131 } \
132}; \
133static LATTR_MAKE_UNIQUE_ID(getter_adder_, id, obj_name) LATTR_MAKE_UNIQUE_ID(getter_adder_instance_, id, obj_name) ; \
134value_type LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name)::get([[maybe_unused]] lua_State* L, const LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name)::object_type& obj_name) const
135
136
137#define LATTR_SETTER5(name, value_type, obj_type, obj_name, id) \
138struct LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name) : public lua_setter<obj_type, value_type> { \
139 using object_type = obj_type; \
140 void set(lua_State* L, object_type& obj_name, const value_type& value) const override; \
141}; \
142struct LATTR_MAKE_UNIQUE_ID(setter_adder_, id, obj_name) { \
143 LATTR_MAKE_UNIQUE_ID(setter_adder_, id, obj_name) ()\
144 { \
145 register_lua_attribute<obj_type, value_type, LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name), lua_attrfunc_type::setter>(name); \
146 } \
147}; \
148static LATTR_MAKE_UNIQUE_ID(setter_adder_, id, obj_name) LATTR_MAKE_UNIQUE_ID(setter_adder_instance_, id, obj_name); \
149void LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name)::set([[maybe_unused]] lua_State* L, LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name)::object_type& obj_name, const value_type& value) const
150
151
152#define LATTR_VALID5(name, obj_type, obj_name, id) \
153struct LATTR_MAKE_UNIQUE_ID(check_, id, obj_name) : public lua_validator<obj_type> { \
154 using object_type = obj_type; \
155 bool is_active(lua_State* L, const object_type& obj_name) const override; \
156}; \
157struct LATTR_MAKE_UNIQUE_ID(check_adder_, id, obj_name) { \
158 LATTR_MAKE_UNIQUE_ID(check_adder_, id, obj_name) ()\
159 { \
160 register_lua_attribute<obj_type, void, LATTR_MAKE_UNIQUE_ID(check_, id, obj_name), lua_attrfunc_type::validator>(name); \
161 } \
162}; \
163static LATTR_MAKE_UNIQUE_ID(check_adder_, id, obj_name) LATTR_MAKE_UNIQUE_ID(check_adder_instance_, id, obj_name); \
164bool LATTR_MAKE_UNIQUE_ID(check_, id, obj_name)::is_active([[maybe_unused]] lua_State* L, const LATTR_MAKE_UNIQUE_ID(check_, id, obj_name)::object_type& obj_name) const
165
166
167/**
168 * @param name: string attribute name
169 * @param value_type: the type of the attribute, for example int or std::string
170 * @param obj_type: the type of the object, for example lua_unit
171 * @param obj_name: a name for the variable that will hold the object
172 */
173#define LATTR_GETTER(name, value_type, obj_type, obj_name) LATTR_GETTER5(name, value_type, obj_type, obj_name, __LINE__)
174
175#define LATTR_SETTER(name, value_type, obj_type, obj_name) LATTR_SETTER5(name, value_type, obj_type, obj_name, __LINE__)
176
177#define LATTR_VALID(name, obj_type, obj_name) LATTR_VALID5(name, obj_type, obj_name, __LINE__)
A variable-expanding proxy for the config class.
Definition variable.hpp:45
Definitions for the interface to Wesnoth Markup Language (WML).
std::decay_t< T > lua_check(lua_State *L, int n)
lua_attrfunc_type
void register_lua_attribute(const char *name)
void lua_push(lua_State *L, const T &val)
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
getters_list getters
A map of callbacks that read data from the object.
setters_list setters
A map of callbacks that write data to the object.
std::map< std::string, std::function< bool(lua_State *L)> > validators_list
validators_list validators
A map of callbacks that check if a member is available.
static std::map< std::string_view, std::reference_wrapper< luaW_Registry > > lookup
std::string private_metatable
The internal metatable string for the object (from __metatable)
std::map< std::string, std::function< bool(lua_State *L, int idx, bool nop)> > setters_list
std::vector< std::string > public_metatable
Optional external metatable for the object (eg "wesnoth", "units") All entries of this table will be ...
luaW_Registry()=delete
int set(lua_State *L)
Implement __newindex metamethod.
int get(lua_State *L)
Implement __index metamethod.
std::map< std::string, std::function< bool(lua_State *L, bool nop)> > getters_list
virtual value_type get(lua_State *L, const object_type &obj) const =0
virtual ~lua_getter()=default
virtual void set(lua_State *L, object_type &obj, const value_type &value) const =0
virtual ~lua_setter()=default
virtual bool is_active(lua_State *L, const object_type &obj) const =0
virtual ~lua_validator()=default
static map_location::direction n