Freeciv21
Develop your civilization from humble roots to a global empire
script_server.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2020 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 #include <cstdarg>
12 #include <ctime>
13 #include <sys/stat.h>
14 
15 /* dependencies/lua */
16 extern "C" {
17 #include "lua.h"
18 
19 /* dependencies/tolua */
20 #include "tolua.h"
21 }
22 // utility
23 #include "log.h"
24 #include "registry.h"
25 #include "registry_ini.h"
26 
27 /* common/scriptcore */
28 #include "api_game_specenum.h"
29 #include "luascript.h"
30 #include "luascript_func.h"
31 #include "luascript_signal.h"
32 #include "tolua_game_gen.h"
33 #include "tolua_signal_gen.h"
34 // server
35 #include "console.h"
36 #include "stdinhand.h"
37 
38 /* server/scripting */
39 #include "tolua_server_gen.h"
40 
41 #include "script_server.h"
42 
46 static struct fc_lua *fcl_main = nullptr;
47 static struct fc_lua *fcl_unsafe = nullptr;
48 
52 static char *script_server_code = nullptr;
53 
54 static void script_server_vars_init();
55 static void script_server_vars_free();
56 static void script_server_vars_load(struct section_file *file);
57 static void script_server_vars_save(struct section_file *file);
58 static void script_server_code_init();
59 static void script_server_code_free();
60 static void script_server_code_load(struct section_file *file);
61 static void script_server_code_save(struct section_file *file);
62 
63 static void script_server_signals_create();
64 static void script_server_functions_define();
65 
66 static void script_server_cmd_reply(struct fc_lua *fcl, QtMsgType level,
67  const char *format, ...)
68  fc__attribute((__format__(__printf__, 3, 4)));
69 
75  struct connection *caller,
76  const char *str)
77 {
78  int status;
79  struct connection *save_caller;
80  luascript_log_func_t save_output_fct;
81 
82  /* Set a log callback function which allows to send the results of the
83  * command to the clients. */
84  save_caller = fcl->caller;
85  save_output_fct = fcl->output_fct;
86  fcl->output_fct = script_server_cmd_reply;
87  fcl->caller = caller;
88 
89  status = luascript_do_string(fcl, str, "cmd");
90 
91  // Reset the changes.
92  fcl->caller = save_caller;
93  fcl->output_fct = save_output_fct;
94 
95  return (status == 0);
96 }
97 
101 bool script_server_do_string(struct connection *caller, const char *str)
102 {
103  return script_server_do_string_shared(fcl_main, caller, str);
104 }
105 
110  const char *str)
111 {
112  return script_server_do_string_shared(fcl_unsafe, caller, str);
113 }
114 
118 bool script_server_load_file(const char *filename, char **buf)
119 {
120  FILE *ffile;
121  struct stat stats;
122  char *buffer;
123 
124  fc_stat(filename, &stats);
125  ffile = fc_fopen(filename, "r");
126 
127  if (ffile != nullptr) {
128  int len;
129 
130  buffer = new char[stats.st_size + 1];
131  len = fread(buffer, 1, stats.st_size, ffile);
132 
133  if (len == stats.st_size) {
134  buffer[len] = '\0';
135 
136  *buf = buffer;
137  } else {
138  delete[] buffer;
139  }
140  fclose(ffile);
141  }
142 
143  return true;
144 }
145 
151  struct connection *caller,
152  const char *filename)
153 {
154  int status = 1;
155  struct connection *save_caller;
156  luascript_log_func_t save_output_fct;
157 
158  /* Set a log callback function which allows to send the results of the
159  * command to the clients. */
160  save_caller = fcl->caller;
161  save_output_fct = fcl->output_fct;
162  fcl->output_fct = script_server_cmd_reply;
163  fcl->caller = caller;
164 
165  status = luascript_do_file(fcl, filename);
166 
167  // Reset the changes.
168  fcl->caller = save_caller;
169  fcl->output_fct = save_output_fct;
170 
171  return (status == 0);
172 }
173 
178 bool script_server_do_file(struct connection *caller, const char *filename)
179 {
180  return script_server_do_file_shared(fcl_main, caller, filename);
181 }
182 
187  const char *filename)
188 {
189  return script_server_do_file_shared(fcl_unsafe, caller, filename);
190 }
191 
198 {
201 }
202 
207 { // nothing
208 }
209 
214 { // nothing
215 }
216 
220 static void script_server_vars_load(struct section_file *file)
221 {
222  luascript_vars_load(fcl_main, file, "script.vars");
223 }
224 
228 static void script_server_vars_save(struct section_file *file)
229 {
230  luascript_vars_save(fcl_main, file, "script.vars");
231 }
232 
236 static void script_server_code_init() { script_server_code = nullptr; }
237 
242 {
243  if (script_server_code) {
244  delete[] script_server_code;
245  script_server_code = nullptr;
246  }
247 }
248 
252 static void script_server_code_load(struct section_file *file)
253 {
254  if (!script_server_code) {
255  const char *code;
256  const char *section = "script.code";
257 
258  code = secfile_lookup_str_default(file, "", "%s", section);
261  }
262 }
263 
267 static void script_server_code_save(struct section_file *file)
268 {
269  if (script_server_code) {
270  secfile_insert_str_noescape(file, script_server_code, "script.code");
271  }
272 }
273 
278 {
279  if (fcl_main != nullptr) {
280  fc_assert_ret_val(fcl_main->state != nullptr, false);
281 
282  return true;
283  }
284 
285  fcl_main = luascript_new(nullptr, true);
286  if (fcl_main == nullptr) {
288  fcl_main = nullptr;
289 
290  return false;
291  }
292 
295  tolua_game_open(fcl_main->state);
296  tolua_signal_open(fcl_main->state);
297 
298  tolua_server_open(fcl_main->state);
299 
301 
304 
307 
310 
311  // Add the unsafe instance.
312  fcl_unsafe = luascript_new(nullptr, false);
313  if (fcl_unsafe == nullptr) {
315  fcl_unsafe = nullptr;
316 
317  return false;
318  }
319 
322  tolua_game_open(fcl_unsafe->state);
323 
324  tolua_server_open(fcl_unsafe->state);
325 
327 
330 
331  return true;
332 }
333 
338 {
339  if (fcl_main != nullptr) {
342 
343  // luascript_signal_free() is called by luascript_destroy().
345  fcl_main = nullptr;
346  }
347 
348  if (fcl_unsafe != nullptr) {
349  // luascript_signal_free() is called by luascript_destroy().
351  fcl_unsafe = nullptr;
352  }
353 }
354 
359 {
361 
362  /* Variables must be loaded after code is loaded and executed,
363  * so we restore their saved state properly */
365 }
366 
371 {
374 }
375 
379 void script_server_signal_emit(const char *signal_name, ...)
380 {
381  va_list args;
382 
383  va_start(args, signal_name);
384  luascript_signal_emit_valist(fcl_main, signal_name, args);
385  va_end(args);
386 }
387 
392 {
393  signal_deprecator *depr;
394 
395  luascript_signal_create(fcl_main, "turn_begin", 2, API_TYPE_INT,
396  API_TYPE_INT);
397 
398  /* Deprecated form of the 'turn_begin' signal that counts real turns
399  * starting from 0. */
400  depr = luascript_signal_create(fcl_main, "turn_started", 2, API_TYPE_INT,
401  API_TYPE_INT);
402  deprecate_signal(depr, "turn_started", "turn_begin", "3.0");
403 
404  luascript_signal_create(fcl_main, "unit_moved", 3, API_TYPE_UNIT,
405  API_TYPE_TILE, API_TYPE_TILE);
406 
407  // Includes all newly-built cities.
408  luascript_signal_create(fcl_main, "city_built", 1, API_TYPE_CITY);
409 
410  luascript_signal_create(fcl_main, "city_size_change", 3, API_TYPE_CITY,
411  API_TYPE_INT, API_TYPE_STRING);
412 
413  /* Deprecated form of the 'city_size_change' signal for the case of growth.
414  */
415  depr = luascript_signal_create(fcl_main, "city_growth", 2, API_TYPE_CITY,
416  API_TYPE_INT);
417  deprecate_signal(depr, "city_growth", "city_size_change", "2.6");
418 
419  // Only includes units built in cities, for now.
420  luascript_signal_create(fcl_main, "unit_built", 2, API_TYPE_UNIT,
421  API_TYPE_CITY);
422  luascript_signal_create(fcl_main, "building_built", 2,
423  API_TYPE_BUILDING_TYPE, API_TYPE_CITY);
424 
425  /* These can happen for various reasons; the third argument gives the
426  * reason (a simple string identifier). Example identifiers:
427  * "pop_cost", "need_tech", "need_building", "need_special",
428  * "need_terrain", "need_government", "need_nation", "never",
429  * "unavailable". */
430  luascript_signal_create(fcl_main, "unit_cant_be_built", 3,
431  API_TYPE_UNIT_TYPE, API_TYPE_CITY,
432  API_TYPE_STRING);
433  luascript_signal_create(fcl_main, "building_cant_be_built", 3,
434  API_TYPE_BUILDING_TYPE, API_TYPE_CITY,
435  API_TYPE_STRING);
436 
437  /* Third argument gives a reason; "landlocked", "cant_maintain",
438  * "obsolete", "sold", "disaster", "sabotaged", "razed", "city_destroyed",
439  * "conquered" (applicable for small wonders only)
440  * Fourth argument gives unit that caused that, applicable for "sabotaged"
441  */
442  luascript_signal_create(fcl_main, "building_lost", 4, API_TYPE_CITY,
443  API_TYPE_BUILDING_TYPE, API_TYPE_STRING,
444  API_TYPE_UNIT);
445 
446  /* The third argument contains the source: "researched", "traded",
447  * "stolen", "hut". */
448  luascript_signal_create(fcl_main, "tech_researched", 3, API_TYPE_TECH_TYPE,
449  API_TYPE_PLAYER, API_TYPE_STRING);
450 
451  // First player is city owner, second is enemy.
452  luascript_signal_create(fcl_main, "city_destroyed", 3, API_TYPE_CITY,
453  API_TYPE_PLAYER, API_TYPE_PLAYER);
454 
455  // First player is former owner, second new one.
456  luascript_signal_create(fcl_main, "city_transferred", 4, API_TYPE_CITY,
457  API_TYPE_PLAYER, API_TYPE_PLAYER, API_TYPE_STRING);
458 
459  /* Deprecated form of the 'city_transferred' signal for the case of
460  * conquest. */
461  depr = luascript_signal_create(fcl_main, "city_lost", 3, API_TYPE_CITY,
462  API_TYPE_PLAYER, API_TYPE_PLAYER);
463  deprecate_signal(depr, "city_lost", "city_transferred", "2.6");
464 
465  luascript_signal_create(fcl_main, "hut_enter", 2, API_TYPE_UNIT,
466  API_TYPE_STRING);
467  luascript_signal_create(fcl_main, "hut_frighten", 2, API_TYPE_UNIT,
468  API_TYPE_STRING);
469 
470  luascript_signal_create(fcl_main, "unit_lost", 3, API_TYPE_UNIT,
471  API_TYPE_PLAYER, API_TYPE_STRING);
472 
473  luascript_signal_create(fcl_main, "disaster_occurred", 3,
474  API_TYPE_DISASTER, API_TYPE_CITY, API_TYPE_BOOL);
475 
476  luascript_signal_create(fcl_main, "nuke_exploded", 2, API_TYPE_TILE,
477  API_TYPE_PLAYER);
478 
479  /* Deprecated form of the 'disaster_occurred' signal without
480  * 'had_internal_effct' support. */
481  depr = luascript_signal_create(fcl_main, "disaster", 2, API_TYPE_DISASTER,
482  API_TYPE_CITY);
483  deprecate_signal(depr, "disaster", "disaster_occurred", "2.6");
484 
485  luascript_signal_create(fcl_main, "achievement_gained", 3,
486  API_TYPE_ACHIEVEMENT, API_TYPE_PLAYER,
487  API_TYPE_BOOL);
488 
489  luascript_signal_create(fcl_main, "map_generated", 0);
490 
491  luascript_signal_create(fcl_main, "pulse", 0);
492 
493  luascript_signal_create(fcl_main, "action_started_unit_unit", 3,
494  API_TYPE_ACTION, API_TYPE_UNIT, API_TYPE_UNIT);
495 
496  luascript_signal_create(fcl_main, "action_started_unit_units", 3,
497  API_TYPE_ACTION, API_TYPE_UNIT, API_TYPE_TILE);
498 
499  luascript_signal_create(fcl_main, "action_started_unit_city", 3,
500  API_TYPE_ACTION, API_TYPE_UNIT, API_TYPE_CITY);
501 
502  luascript_signal_create(fcl_main, "action_started_unit_tile", 3,
503  API_TYPE_ACTION, API_TYPE_UNIT, API_TYPE_TILE);
504 
505  luascript_signal_create(fcl_main, "action_started_unit_self", 2,
506  API_TYPE_ACTION, API_TYPE_UNIT);
507 }
508 
517 {
518  luascript_func_add(fcl_main, "respawn_callback", false, 1, 0,
519  API_TYPE_PLAYER);
520 }
521 
525 bool script_server_call(const char *func_name, ...)
526 {
527  bool success;
528 
529  va_list args;
530  va_start(args, func_name);
531  success = luascript_func_call_valist(fcl_main, func_name, args);
532  va_end(args);
533 
534  return success;
535 }
536 
540 static void script_server_cmd_reply(struct fc_lua *fcl, QtMsgType level,
541  const char *format, ...)
542 {
543  va_list args;
544  enum rfc_status rfc_status = C_OK;
545  char buf[1024];
546 
547  va_start(args, format);
548  fc_vsnprintf(buf, sizeof(buf), format, args);
549  va_end(args);
550 
551  switch (level) {
552  case LOG_FATAL:
553  // Special case - will quit the server.
554  qFatal("%s", buf);
555  break;
556  case LOG_ERROR:
557  case LOG_WARN:
559  break;
560  case LOG_NORMAL:
562  break;
563  case LOG_VERBOSE:
565  break;
566  }
567 
568  cmd_reply(CMD_LUA, fcl->caller, rfc_status, "%s", buf);
569 }
int api_specenum_open(lua_State *L)
Define the __index function for each exported specenum type.
@ CMD_LUA
Definition: commands.h:95
rfc_status
Definition: console.h:36
@ C_OK
Definition: console.h:41
@ C_LOG_BASE
Definition: console.h:40
@ C_COMMENT
Definition: console.h:37
@ C_WARNING
Definition: console.h:48
static struct @122 stats
constexpr auto LOG_ERROR
Definition: log.h:23
constexpr auto LOG_VERBOSE
Definition: log.h:26
constexpr auto LOG_NORMAL
Definition: log.h:25
constexpr auto LOG_WARN
Definition: log.h:24
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
constexpr auto LOG_FATAL
Definition: log.h:22
void luascript_remove_exported_object(struct fc_lua *fcl, void *object)
Mark any, if exported, full userdata representing 'object' in the current script state as 'Nonexisten...
Definition: luascript.cpp:699
int luascript_do_string(struct fc_lua *fcl, const char *str, const char *name)
lua_dostring replacement with error message showing on errors.
Definition: luascript.cpp:618
int luascript_do_file(struct fc_lua *fcl, const char *filename)
Parse and execute the script at filename.
Definition: luascript.cpp:638
void luascript_vars_load(struct fc_lua *fcl, struct section_file *file, const char *section)
Load lua variables from file.
Definition: luascript.cpp:763
void luascript_common_z(lua_State *L)
Runs tolua_common_z.lua.
Definition: luascript.cpp:420
struct fc_lua * luascript_new(luascript_log_func_t output_fct, bool secured_environment)
Initialize the scripting state.
Definition: luascript.cpp:272
void luascript_vars_save(struct fc_lua *fcl, struct section_file *file, const char *section)
Save lua variables to file.
Definition: luascript.cpp:737
void luascript_common_a(lua_State *L)
Runs tolua_common_a.lua.
Definition: luascript.cpp:410
void luascript_destroy(struct fc_lua *fcl)
Free the scripting data.
Definition: luascript.cpp:335
void(* luascript_log_func_t)(struct fc_lua *fcl, QtMsgType level, const char *format,...) fc__attribute((__format__(__printf__
Definition: luascript.h:33
bool luascript_func_call_valist(struct fc_lua *fcl, const char *func_name, va_list args)
Call a lua function; return value is TRUE if no errors occurred, otherwise FALSE.
void luascript_func_init(struct fc_lua *fcl)
Initialize the structures needed to save functions definitions.
void luascript_func_add(struct fc_lua *fcl, const char *func_name, bool required, int nargs, int nreturns,...)
Add a lua function.
void luascript_signal_init(struct fc_lua *fcl)
Initialize script signals and callbacks.
signal_deprecator * luascript_signal_create(struct fc_lua *fcl, const char *signal_name, int nargs,...)
Create a new signal type.
void deprecate_signal(signal_deprecator *deprecator, const char *signal_name, const char *replacement, const char *deprecated_since)
Mark signal deprecated.
void luascript_signal_emit_valist(struct fc_lua *fcl, const char *signal_name, va_list args)
Invoke all the callback functions attached to a given signal.
char * signal_deprecator
int len
Definition: packhand.cpp:127
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
#define secfile_insert_str_noescape(secfile, string, path,...)
Definition: registry_ini.h:170
static void static sol::state * fcl
Lua virtual machine state.
Definition: script_fcdb.cpp:48
static bool script_server_do_file_shared(struct fc_lua *fcl, struct connection *caller, const char *filename)
Parse and execute the script at filename in the context of the specified instance.
static void script_server_vars_init()
Initialize the game script variables.
bool script_server_unsafe_do_string(struct connection *caller, const char *str)
Parse and execute the script in str in an unsafe instance.
static void script_server_code_free()
Free the optional game script code (useful for scenarios).
static char * script_server_code
Optional game script code (useful for scenarios).
static void script_server_vars_free()
Free the game script variables.
static void static bool script_server_do_string_shared(struct fc_lua *fcl, struct connection *caller, const char *str)
Parse and execute the script in str in the context of the specified instance.
void script_server_signal_emit(const char *signal_name,...)
Invoke all the callback functions attached to a given signal.
bool script_server_init()
Initialize the scripting state.
bool script_server_do_string(struct connection *caller, const char *str)
Parse and execute the script in str in the same instance as the ruleset.
static void script_server_vars_load(struct section_file *file)
Load the game script variables in file.
static void script_server_code_init()
Initialize the optional game script code (useful for scenarios).
static struct fc_lua * fcl_main
Lua virtual machine states.
bool script_server_call(const char *func_name,...)
Call a lua function.
static void script_server_code_save(struct section_file *file)
Save the optional game script code to file (useful for scenarios).
void script_server_state_save(struct section_file *file)
Save the scripting state to file.
static void script_server_vars_save(struct section_file *file)
Save the game script variables to file.
void script_server_free()
Free the scripting data.
void script_server_state_load(struct section_file *file)
Load the scripting state from file.
void script_server_remove_exported_object(void *object)
Mark any, if exported, full userdata representing 'object' in the current script state as 'Nonexisten...
static struct fc_lua * fcl_unsafe
static void script_server_functions_define()
Add server callback functions; these must be defined in the lua script '[rulesetdir]/script....
static void script_server_signals_create()
Declare any new signal types you need here.
static void script_server_cmd_reply(struct fc_lua *fcl, QtMsgType level, const char *format,...) fc__attribute((__format__(__printf__
Send the message via cmd_reply().
static void script_server_code_load(struct section_file *file)
Load the optional game script code from file (useful for scenarios).
bool script_server_unsafe_do_file(struct connection *caller, const char *filename)
Parse and execute the script at filename in an unsafe instance.
bool script_server_load_file(const char *filename, char **buf)
Load script to a buffer.
bool script_server_do_file(struct connection *caller, const char *filename)
Parse and execute the script at filename in the same instance as the ruleset.
struct setting_list * level[OLEVELS_NUM]
Definition: settings.cpp:167
void cmd_reply(enum command_id cmd, struct connection *caller, enum rfc_status rfc_status, const char *format,...)
var-args version as above, no prefix
Definition: stdinhand.cpp:393
enum auth_status status
Definition: connection.h:203
struct connection * caller
Definition: luascript.h:42
lua_State * state
Definition: luascript.h:38
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition: support.cpp:512
int fc_stat(const char *filename, struct stat *buf)
Wrapper function for stat() with filename conversion to local encoding on Windows.
Definition: support.cpp:293
FILE * fc_fopen(const char *filename, const char *opentype)
Wrapper function for fopen() with filename conversion to local encoding on Windows.
Definition: support.cpp:255
int fc__attribute((nonnull(1, 3)))
#define fc_strdup(str)
Definition: support.h:111