The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
manager.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
3 by Chris Beck <render787@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
17
19#include <cassert>
20#include <stdexcept>
21#include <string>
22#include <vector>
23
24#include "log.hpp"
25
26static lg::log_domain log_plugins("plugins");
27#define DBG_PLG LOG_STREAM(debug, log_plugins)
28#define LOG_PLG LOG_STREAM(info, log_plugins)
29#define WRN_PLG LOG_STREAM(warn, log_plugins)
30#define ERR_PLG LOG_STREAM(err, log_plugins)
31
32struct plugin
33{
34 std::string name;
35 std::string source;
36 bool is_file;
37 std::unique_ptr<application_lua_kernel::thread> thread;
38 std::vector<plugins_manager::event> queue;
39};
40
41static plugins_manager * singleton = nullptr;
42
44 : plugins_()
45 , playing_()
46 , kernel_(kernel)
47{
48 assert(!singleton);
49 singleton = this;
50
51 kernel_->load_core();
52 add_plugin("Null Plugin", "return function() end");
53 start_plugin(0);
54}
55
57
62
67
68std::size_t plugins_manager::size() {
69 return plugins_.size();
70}
71
72plugin_manager_status::type plugins_manager::get_status(std::size_t idx) {
73 if (idx < plugins_.size()) {
74 if (!plugins_[idx].thread) {
75 return plugin_manager_status::type::not_created;
76 } else {
77 return plugins_[idx].thread->is_running() ? plugin_manager_status::type::running : plugin_manager_status::type::stopped;
78 }
79 }
80 throw std::runtime_error("index out of bounds");
81}
82
83std::string plugins_manager::get_detailed_status(std::size_t idx) {
84 if (idx < plugins_.size()) {
85 if (!plugins_[idx].thread) {
86 return "not loaded";
87 } else {
88 return plugins_[idx].thread->status();
89 }
90 }
91 throw std::runtime_error("index out of bounds");
92}
93
94std::string plugins_manager::get_name(std::size_t idx) {
95 if (idx < plugins_.size()) {
96 return plugins_[idx].name;
97 }
98 throw std::runtime_error("index out of bounds");
99}
100
101void plugins_manager::start_plugin(std::size_t idx)
102{
103 DBG_PLG << "start_plugin[" << idx <<"]";
104 if (idx < plugins_.size()) {
105 if (!plugins_[idx].thread) {
106 DBG_PLG << "creating thread[" << idx << "]";
107 plugins_[idx].thread.reset(plugins_[idx].is_file ?
108 kernel_->load_script_from_file(plugins_[idx].source) : kernel_->load_script_from_string(plugins_[idx].source));
109 DBG_PLG << "finished [" << idx << "], status = '" << plugins_[idx].thread->status() << "'";
110 } else {
111 DBG_PLG << "thread already exists, skipping";
112 }
113 return ;
114 }
115 throw std::runtime_error("index out of bounds");
116}
117
118std::size_t plugins_manager::add_plugin(const std::string & name, const std::string & prog)
119{
120 std::size_t idx = plugins_.size();
121 plugins_.emplace_back();
122
123 plugin & p = plugins_[idx];
124 p.name = name;
125 p.source = prog;
126 p.is_file = false;
127
128 return idx;
129}
130
131std::size_t plugins_manager::load_plugin(const std::string & name, const std::string & filename)
132{
133 std::size_t idx = plugins_.size();
134 plugins_.emplace_back();
135
136 plugin & p = plugins_[idx];
137 p.name = name;
138 p.source = filename;
139 p.is_file = true;
140
141 return idx;
142}
143
144void plugins_manager::notify_event(const std::string & name, const config & data)
145{
146 event evt;
147 evt.name = name;
148 evt.data = data;
149
150 for (std::size_t idx = 0; idx < size(); ++idx)
151 {
152 if (plugins_[idx].thread && plugins_[idx].thread->is_running()) {
153 plugins_[idx].queue.push_back(evt);
154 }
155 }
156}
157
159{
160 if (playing_) {
161 *playing_ = false; //this is to ensure "reentrancy" -- any previous calls to this function that never returned
162 //and looped back into the plugins system, should be halted and their later requests discarded
163 //this is to ensure the semantics that if a plugins context is left, then any pending requests
164 //are discarded to prevent them from being executed at an improper time
165 }
166 playing_ = std::make_shared<bool> (true);
167 std::shared_ptr<bool> local = playing_; //make a local copy of the pointer on the stack
168
169 for (std::size_t idx = 0; idx < size(); ++idx)
170 {
171 DBG_PLG << "play_slice[" << idx << "] ...";
172 if (plugins_[idx].thread && plugins_[idx].thread->is_running()) {
173 DBG_PLG << "is running...";
174 if (!*local) { //check playing_ before each call to be sure that we should still continue
175 DBG_PLG << "aborting";
176 return;
177 }
178
179 std::vector<event> input = plugins_[idx].queue; //empty the queue to a temporary variable
180 plugins_[idx].queue = std::vector<event>();
181
182 //application_lua_kernel::requests_list requests =
183 std::vector<std::function<bool(void)>> requests =
184 plugins_[idx].thread->run_script(ctxt, input);
185
186 DBG_PLG << "thread returned " << requests.size() << " requests";
187
188 for (std::size_t j = 0; j < requests.size(); ++j) {
189 if (!*local) return; //check playing_ before each call to be sure that we should still continue
190 if (!requests[j]()) {
191 *local = false;
192 return ; //call the function but if it returns false (error) then stop
193 }
194 }
195
196 DBG_PLG << "play_slice[" << idx << "] finished.";
197 } else if (!plugins_[idx].thread) {
198 DBG_PLG << "thread ["<< idx << "] not created";
199 } else {
200 DBG_PLG << "thread ["<< idx << "] not running";
201 }
202 }
203 *local = false;
204}
205
207{
208
209 for (std::size_t i = 0; i < size(); ++i) {
210 if (plugin_manager_status::type::running == get_status(i)) {
211 return true;
212 }
213 }
214 return false;
215}
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
std::size_t size()
Definition manager.cpp:68
void notify_event(const std::string &name, const config &data)
Definition manager.cpp:144
std::unique_ptr< application_lua_kernel > kernel_
Definition manager.hpp:67
plugin_manager_status::type get_status(std::size_t idx)
Definition manager.cpp:72
std::string get_name(std::size_t idx)
Definition manager.cpp:94
static plugins_manager * get()
Definition manager.cpp:58
void start_plugin(std::size_t idx)
Definition manager.cpp:101
bool any_running()
Definition manager.cpp:206
std::size_t load_plugin(const std::string &name, const std::string &filename)
Definition manager.cpp:131
std::string get_detailed_status(std::size_t idx)
Definition manager.cpp:83
std::shared_ptr< bool > playing_
Definition manager.hpp:66
void play_slice(const plugins_context &)
Definition manager.cpp:158
lua_kernel_base * get_kernel_base()
Definition manager.cpp:63
std::vector< plugin > plugins_
Definition manager.hpp:65
plugins_manager(application_lua_kernel *)
Definition manager.cpp:43
std::size_t add_plugin(const std::string &name, const std::string &prog)
Definition manager.cpp:118
static game_config_manager * singleton
Standard logging facilities (interface).
std::string_view data
Definition picture.cpp:188
#define DBG_PLG
Definition manager.cpp:27
static plugins_manager * singleton
Definition manager.cpp:41
static lg::log_domain log_plugins("plugins")
std::string filename
Filename.
std::string name
Definition manager.cpp:34
std::vector< plugins_manager::event > queue
Definition manager.cpp:38
std::string source
Definition manager.cpp:35
bool is_file
Definition manager.cpp:36
std::unique_ptr< application_lua_kernel::thread > thread
Definition manager.cpp:37
mock_party p
#define i