1 /*****************************************************************************
2  Freeciv - Copyright (C) 2005 - The Freeciv Project
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 *****************************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <time.h>
21 
22 /* dependencies/lua */
23 #include "lua.h"
24 #include "lualib.h"
25 
26 /* dependencies/tolua */
27 #include "tolua.h"
28 
29 /* utility */
30 #include "astring.h"
31 #include "log.h"
32 #include "mem.h"
33 #include "registry.h"
34 
35 /* common/scriptcore */
36 #include "api_game_specenum.h"
37 #include "luascript.h"
38 #include "luascript_signal.h"
39 #include "luascript_func.h"
40 #include "tolua_common_a_gen.h"
41 #include "tolua_common_z_gen.h"
42 #include "tolua_game_gen.h"
43 #include "tolua_signal_gen.h"
44 
45 /* server */
46 #include "console.h"
47 #include "stdinhand.h"
48 
49 /* server/scripting */
50 #include "tolua_server_gen.h"
51 
52 #include "script_server.h"
53 
54 /*****************************************************************************
55   Lua virtual machine state.
56 *****************************************************************************/
57 static struct fc_lua *fcl_main = NULL;
58 
59 /*****************************************************************************
60   Optional game script code (useful for scenarios).
61 *****************************************************************************/
62 static char *script_server_code = NULL;
63 
64 static void script_server_vars_init(void);
65 static void script_server_vars_free(void);
66 static void script_server_vars_load(struct section_file *file);
67 static void script_server_vars_save(struct section_file *file);
68 static void script_server_code_init(void);
69 static void script_server_code_free(void);
70 static void script_server_code_load(struct section_file *file);
71 static void script_server_code_save(struct section_file *file);
72 
73 static void script_server_signals_create(void);
74 static void script_server_functions_define(void);
75 
76 static void script_server_cmd_reply(struct fc_lua *fcl, enum log_level level,
77                                     const char *format, ...)
78             fc__attribute((__format__ (__printf__, 3, 4)));
79 
80 /*****************************************************************************
81   Parse and execute the script in str
82 *****************************************************************************/
script_server_do_string(struct connection * caller,const char * str)83 bool script_server_do_string(struct connection *caller, const char *str)
84 {
85   int status;
86   struct connection *save_caller;
87   luascript_log_func_t save_output_fct;
88 
89   /* Set a log callback function which allows to send the results of the
90    * command to the clients. */
91   save_caller = fcl_main->caller;
92   save_output_fct = fcl_main->output_fct;
93   fcl_main->output_fct = script_server_cmd_reply;
94   fcl_main->caller = caller;
95 
96   status = luascript_do_string(fcl_main, str, "cmd");
97 
98   /* Reset the changes. */
99   fcl_main->caller = save_caller;
100   fcl_main->output_fct = save_output_fct;
101 
102   return (status == 0);
103 }
104 
105 /*****************************************************************************
106   Load script to a buffer
107 *****************************************************************************/
script_server_load_file(const char * filename,char ** buf)108 bool script_server_load_file(const char *filename, char **buf)
109 {
110   FILE *ffile;
111   struct stat stats;
112   char *buffer;
113 
114   fc_stat(filename, &stats);
115   ffile = fc_fopen(filename, "r");
116 
117   if (ffile != NULL) {
118     int len;
119 
120     buffer = fc_malloc(stats.st_size + 1);
121 
122     len = fread(buffer, 1, stats.st_size, ffile);
123 
124     if (len == stats.st_size) {
125       buffer[len] = '\0';
126 
127       *buf = buffer;
128     }
129     fclose(ffile);
130   }
131 
132   return 1;
133 }
134 
135 /*****************************************************************************
136   Parse and execute the script at filename.
137 *****************************************************************************/
script_server_do_file(struct connection * caller,const char * filename)138 bool script_server_do_file(struct connection *caller, const char *filename)
139 {
140   int status = 1;
141   struct connection *save_caller;
142   luascript_log_func_t save_output_fct;
143 
144   /* Set a log callback function which allows to send the results of the
145    * command to the clients. */
146   save_caller = fcl_main->caller;
147   save_output_fct = fcl_main->output_fct;
148   fcl_main->output_fct = script_server_cmd_reply;
149   fcl_main->caller = caller;
150 
151   status = luascript_do_file(fcl_main, filename);
152 
153   /* Reset the changes. */
154   fcl_main->caller = save_caller;
155   fcl_main->output_fct = save_output_fct;
156 
157   return (status == 0);
158 }
159 
160 /*****************************************************************************
161   Invoke the 'callback_name' Lua function.
162 *****************************************************************************/
script_server_callback_invoke(const char * callback_name,int nargs,enum api_types * parg_types,va_list args)163 bool script_server_callback_invoke(const char *callback_name, int nargs,
164                                    enum api_types *parg_types, va_list args)
165 {
166   return luascript_callback_invoke(fcl_main, callback_name, nargs, parg_types,
167                                    args);
168 }
169 
170 /*****************************************************************************
171   Mark any, if exported, full userdata representing 'object' in
172   the current script state as 'Nonexistent'.
173   This changes the type of the lua variable.
174 *****************************************************************************/
script_server_remove_exported_object(void * object)175 void script_server_remove_exported_object(void *object)
176 {
177   luascript_remove_exported_object(fcl_main, object);
178 }
179 
180 /*****************************************************************************
181   Initialize the game script variables.
182 *****************************************************************************/
script_server_vars_init(void)183 static void script_server_vars_init(void)
184 {
185   /* nothing */
186 }
187 
188 /*****************************************************************************
189   Free the game script variables.
190 *****************************************************************************/
script_server_vars_free(void)191 static void script_server_vars_free(void)
192 {
193   /* nothing */
194 }
195 
196 /*****************************************************************************
197   Load the game script variables in file.
198 *****************************************************************************/
script_server_vars_load(struct section_file * file)199 static void script_server_vars_load(struct section_file *file)
200 {
201   luascript_vars_load(fcl_main, file, "script.vars");
202 }
203 
204 /*****************************************************************************
205   Save the game script variables to file.
206 *****************************************************************************/
script_server_vars_save(struct section_file * file)207 static void script_server_vars_save(struct section_file *file)
208 {
209   luascript_vars_save(fcl_main, file, "script.vars");
210 }
211 
212 /*****************************************************************************
213   Initialize the optional game script code (useful for scenarios).
214 *****************************************************************************/
script_server_code_init(void)215 static void script_server_code_init(void)
216 {
217   script_server_code = NULL;
218 }
219 
220 /*****************************************************************************
221   Free the optional game script code (useful for scenarios).
222 *****************************************************************************/
script_server_code_free(void)223 static void script_server_code_free(void)
224 {
225   if (script_server_code) {
226     free(script_server_code);
227     script_server_code = NULL;
228   }
229 }
230 
231 /*****************************************************************************
232   Load the optional game script code from file (useful for scenarios).
233 *****************************************************************************/
script_server_code_load(struct section_file * file)234 static void script_server_code_load(struct section_file *file)
235 {
236   if (!script_server_code) {
237     const char *code;
238     const char *section = "script.code";
239 
240     code = secfile_lookup_str_default(file, "", "%s", section);
241     script_server_code = fc_strdup(code);
242     luascript_do_string(fcl_main, script_server_code, section);
243   }
244 }
245 
246 /*****************************************************************************
247   Save the optional game script code to file (useful for scenarios).
248 *****************************************************************************/
script_server_code_save(struct section_file * file)249 static void script_server_code_save(struct section_file *file)
250 {
251   if (script_server_code) {
252     secfile_insert_str_noescape(file, script_server_code, "script.code");
253   }
254 }
255 
256 /*****************************************************************************
257   Initialize the scripting state.
258 *****************************************************************************/
script_server_init(void)259 bool script_server_init(void)
260 {
261   if (fcl_main != NULL) {
262     fc_assert_ret_val(fcl_main->state != NULL, FALSE);
263 
264     return TRUE;
265   }
266 
267   fcl_main = luascript_new(NULL);
268   if (fcl_main == NULL) {
269     luascript_destroy(fcl_main);
270     fcl_main = NULL;
271 
272     return FALSE;
273   }
274 
275   tolua_common_a_open(fcl_main->state);
276   api_specenum_open(fcl_main->state);
277   tolua_game_open(fcl_main->state);
278   tolua_signal_open(fcl_main->state);
279   tolua_server_open(fcl_main->state);
280   tolua_common_z_open(fcl_main->state);
281 
282   script_server_code_init();
283   script_server_vars_init();
284 
285   luascript_signal_init(fcl_main);
286   script_server_signals_create();
287 
288   luascript_func_init(fcl_main);
289   script_server_functions_define();
290 
291   return TRUE;
292 }
293 
294 /*****************************************************************************
295   Free the scripting data.
296 *****************************************************************************/
script_server_free(void)297 void script_server_free(void)
298 {
299   if (fcl_main != NULL) {
300     script_server_code_free();
301     script_server_vars_free();
302 
303     /* luascript_signal_free() is called by luascript_destroy(). */
304     luascript_destroy(fcl_main);
305     fcl_main = NULL;
306   }
307 }
308 
309 /*****************************************************************************
310   Load the scripting state from file.
311 *****************************************************************************/
script_server_state_load(struct section_file * file)312 void script_server_state_load(struct section_file *file)
313 {
314   script_server_code_load(file);
315 
316   /* Variables must be loaded after code is loaded and executed,
317    * so we restore their saved state properly */
318   script_server_vars_load(file);
319 }
320 
321 /*****************************************************************************
322   Save the scripting state to file.
323 *****************************************************************************/
script_server_state_save(struct section_file * file)324 void script_server_state_save(struct section_file *file)
325 {
326   script_server_code_save(file);
327   script_server_vars_save(file);
328 }
329 
330 /*****************************************************************************
331   Invoke all the callback functions attached to a given signal.
332 *****************************************************************************/
script_server_signal_emit(const char * signal_name,int nargs,...)333 void script_server_signal_emit(const char *signal_name, int nargs, ...)
334 {
335   va_list args;
336 
337   va_start(args, nargs);
338   luascript_signal_emit_valist(fcl_main, signal_name, nargs, args);
339   va_end(args);
340 }
341 
342 /*****************************************************************************
343   Declare any new signal types you need here.
344 *****************************************************************************/
script_server_signals_create(void)345 static void script_server_signals_create(void)
346 {
347   signal_deprecator *depr;
348 
349   luascript_signal_create(fcl_main, "turn_started", 2,
350                           API_TYPE_INT, API_TYPE_INT);
351   luascript_signal_create(fcl_main, "unit_moved", 3,
352                           API_TYPE_UNIT, API_TYPE_TILE, API_TYPE_TILE);
353 
354   /* Includes all newly-built cities. */
355   luascript_signal_create(fcl_main, "city_built", 1,
356                           API_TYPE_CITY);
357 
358   luascript_signal_create(fcl_main, "city_size_change", 3,
359                           API_TYPE_CITY, API_TYPE_INT, API_TYPE_STRING);
360 
361   /* Deprecated form of the 'city_size_change' signal for the case of growth. */
362   depr = luascript_signal_create(fcl_main, "city_growth", 2,
363                                  API_TYPE_CITY, API_TYPE_INT);
364   deprecate_signal(depr, "city_growth", "city_size_change", "2.6");
365 
366   /* Only includes units built in cities, for now. */
367   luascript_signal_create(fcl_main, "unit_built", 2,
368                           API_TYPE_UNIT, API_TYPE_CITY);
369   luascript_signal_create(fcl_main, "building_built", 2,
370                           API_TYPE_BUILDING_TYPE, API_TYPE_CITY);
371 
372   /* These can happen for various reasons; the third argument gives the
373    * reason (a simple string identifier).  Example identifiers:
374    * "pop_cost", "need_tech", "need_building", "need_special",
375    * "need_terrain", "need_government", "need_nation", "never",
376    * "unavailable". */
377   luascript_signal_create(fcl_main, "unit_cant_be_built", 3,
378                           API_TYPE_UNIT_TYPE, API_TYPE_CITY, API_TYPE_STRING);
379   luascript_signal_create(fcl_main, "building_cant_be_built", 3,
380                           API_TYPE_BUILDING_TYPE, API_TYPE_CITY,
381                           API_TYPE_STRING);
382 
383   /* The third argument contains the source: "researched", "traded",
384    * "stolen", "hut". */
385   luascript_signal_create(fcl_main, "tech_researched", 3,
386                           API_TYPE_TECH_TYPE, API_TYPE_PLAYER,
387                           API_TYPE_STRING);
388 
389   /* First player is city owner, second is enemy. */
390   luascript_signal_create(fcl_main, "city_destroyed", 3,
391                           API_TYPE_CITY, API_TYPE_PLAYER, API_TYPE_PLAYER);
392 
393   /* First player is former owner, second new one. */
394   luascript_signal_create(fcl_main, "city_transferred", 4,
395                           API_TYPE_CITY, API_TYPE_PLAYER, API_TYPE_PLAYER,
396                           API_TYPE_STRING);
397 
398   /* Deprecated form of the 'city_transferred' signal for the case of
399    * conquest. */
400   depr = luascript_signal_create(fcl_main, "city_lost", 3,
401                                  API_TYPE_CITY, API_TYPE_PLAYER, API_TYPE_PLAYER);
402   deprecate_signal(depr, "city_lost", "city_transferred", "2.6");
403 
404   luascript_signal_create(fcl_main, "hut_enter", 1,
405                           API_TYPE_UNIT);
406 
407   luascript_signal_create(fcl_main, "unit_lost", 3,
408                           API_TYPE_UNIT, API_TYPE_PLAYER, API_TYPE_STRING);
409 
410   luascript_signal_create(fcl_main, "disaster_occurred", 3,
411                           API_TYPE_DISASTER, API_TYPE_CITY, API_TYPE_BOOL);
412 
413   /* Deprecated form of the 'disaster_occurred' signal without 'had_internal_effect'
414    * support. */
415   depr = luascript_signal_create(fcl_main, "disaster", 2,
416                           API_TYPE_DISASTER, API_TYPE_CITY);
417   deprecate_signal(depr, "disaster", "disaster_occurred", "2.6");
418 
419   luascript_signal_create(fcl_main, "achievement_gained", 3,
420                           API_TYPE_ACHIEVEMENT, API_TYPE_PLAYER,
421                           API_TYPE_BOOL);
422 
423   luascript_signal_create(fcl_main, "map_generated", 0);
424 
425   luascript_signal_create(fcl_main, "pulse", 0);
426 
427   luascript_signal_create(fcl_main, "action_started_unit_unit", 3,
428                           API_TYPE_ACTION,
429                           API_TYPE_UNIT, API_TYPE_UNIT);
430 
431   luascript_signal_create(fcl_main, "action_started_unit_city", 3,
432                           API_TYPE_ACTION,
433                           API_TYPE_UNIT, API_TYPE_CITY);
434 }
435 
436 /*****************************************************************************
437   Add server callback functions; these must be defined in the lua script
438   '<rulesetdir>/script.lua':
439 
440   respawn_callback (optional):
441     - callback lua function for the respawn command
442 *****************************************************************************/
script_server_functions_define(void)443 static void script_server_functions_define(void)
444 {
445   luascript_func_add(fcl_main, "respawn_callback", FALSE, 1,
446                      API_TYPE_PLAYER);
447 }
448 
449 /*****************************************************************************
450   Call a lua function.
451 *****************************************************************************/
script_server_call(const char * func_name,int nargs,...)452 bool script_server_call(const char *func_name, int nargs, ...)
453 {
454   bool success;
455   int ret;
456 
457   va_list args;
458   va_start(args, nargs);
459   success = luascript_func_call_valist(fcl_main, func_name, &ret, nargs, args);
460   va_end(args);
461 
462   if (!success) {
463     log_error("Lua function '%s' not defined.", func_name);
464     return FALSE;
465   } else if (!ret) {
466     log_error("Error executing lua function '%s'.", func_name);
467     return FALSE;
468   }
469 
470   return TRUE;
471 }
472 
473 /*****************************************************************************
474   Send the message via cmd_reply().
475 *****************************************************************************/
script_server_cmd_reply(struct fc_lua * fcl,enum log_level level,const char * format,...)476 static void script_server_cmd_reply(struct fc_lua *fcl, enum log_level level,
477                                     const char *format, ...)
478 {
479   va_list args;
480   enum rfc_status rfc_status = C_OK;
481   char buf[1024];
482 
483   va_start(args, format);
484   fc_vsnprintf(buf, sizeof(buf), format, args);
485   va_end(args);
486 
487   switch (level) {
488   case LOG_FATAL:
489     /* Special case - will quit the server. */
490     log_fatal("%s", buf);
491     break;
492   case LOG_ERROR:
493     rfc_status = C_WARNING;
494     break;
495   case LOG_NORMAL:
496     rfc_status = C_COMMENT;
497     break;
498   case LOG_VERBOSE:
499     rfc_status = C_LOG_BASE;
500     break;
501   case LOG_DEBUG:
502     rfc_status = C_DEBUG;
503     break;
504   }
505 
506   cmd_reply(CMD_LUA, fcl->caller, rfc_status, "%s", buf);
507 }
508