Crossfire Server, Trunk
cflogger.cpp
Go to the documentation of this file.
1 /*****************************************************************************/
2 /* Logger plugin version 1.0 alpha. */
3 /* Contact: */
4 /*****************************************************************************/
5 /* That code is placed under the GNU General Public Licence (GPL) */
6 /* (C)2007 by Weeger Nicolas (Feel free to deliver your complaints) */
7 /*****************************************************************************/
8 /* CrossFire, A Multiplayer game for X-windows */
9 /* */
10 /* Copyright (C) 2000 Mark Wedel */
11 /* Copyright (C) 1992 Frank Tore Johansen */
12 /* */
13 /* This program is free software; you can redistribute it and/or modify */
14 /* it under the terms of the GNU General Public License as published by */
15 /* the Free Software Foundation; either version 2 of the License, or */
16 /* (at your option) any later version. */
17 /* */
18 /* This program is distributed in the hope that it will be useful, */
19 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
20 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
21 /* GNU General Public License for more details. */
22 /* */
23 /* You should have received a copy of the GNU General Public License */
24 /* along with this program; if not, write to the Free Software */
25 /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 /* */
27 /*****************************************************************************/
28 
48 #include <cflogger.h>
49 #include <cflogger_proto.h>
50 #include <sqlite3.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <svnversion.h>
54 
56 
58 #define CFLOGGER_CURRENT_FORMAT 3
59 
61 static sqlite3 *database;
62 
64 static int last_stored_day = -1;
65 
81 static int check_tables_callback(void *param, int argc, char **argv, char **azColName) {
82  int *format = (int *)param;
83 
84  *format = atoi(argv[0]);
85  return 0;
86 }
87 
103 static int do_sql(const char *sql) {
104  int err;
105  char *msg;
106 
107  if (!database)
108  return -1;
109 
110  err = sqlite3_exec(database, sql, NULL, NULL, &msg);
111  if (err != SQLITE_OK) {
112  cf_log(llevError, " [%s] error: %d [%s] for sql = %s\n", PLUGIN_NAME, err, msg, sql);
113  sqlite3_free(msg);
114  }
115  return err;
116 }
117 
144 static int update_table_format(const char *table, const char *newschema,
145  const char *select_columns) {
146  char *sql;
147  int err;
148 
149  sql = sqlite3_mprintf("ALTER TABLE %s RENAME TO %s_old;", table, table);
150  err = do_sql(sql);
151  sqlite3_free(sql);
152  if (err != SQLITE_OK)
153  return err;
154 
155  sql = sqlite3_mprintf("CREATE TABLE %s(%s);", table, newschema);
156  err = do_sql(sql);
157  sqlite3_free(sql);
158  if (err != SQLITE_OK)
159  return err;
160 
161  sql = sqlite3_mprintf("INSERT INTO %s SELECT %s FROM %s_old;",
162  table, select_columns, table);
163  err = do_sql(sql);
164  sqlite3_free(sql);
165  if (err != SQLITE_OK)
166  return err;
167 
168  sql = sqlite3_mprintf("DROP TABLE %s_old;", table, table);
169  err = do_sql(sql);
170  sqlite3_free(sql);
171  /* Final return. */
172  return err;
173 }
174 
181 #define DO_OR_ROLLBACK(sqlstring) \
182  if (do_sql(sqlstring) != SQLITE_OK) { \
183  do_sql("rollback transaction;"); \
184  cf_log(llevError, " [%s] Logger database format update failed! Couldn't upgrade from format %d to fromat %d!. Won't log.\n", PLUGIN_NAME, format, CFLOGGER_CURRENT_FORMAT);\
185  sqlite3_close(database); \
186  database = NULL; \
187  return; \
188  }
189 
190 #define UPDATE_OR_ROLLBACK(tbl, newschema, select_columns) \
191  if (update_table_format((tbl), (newschema), (select_columns)) != SQLITE_OK) { \
192  do_sql("rollback transaction;"); \
193  cf_log(llevError, " [%s] Logger database format update failed! Couldn't upgrade from format %d to fromat %d!. Won't log.\n", PLUGIN_NAME, format, CFLOGGER_CURRENT_FORMAT);\
194  sqlite3_close(database); \
195  database = NULL; \
196  return; \
197  }
198 
202 static void check_tables(void) {
203  int format;
204  /*int err;*/
205  format = 0;
206 
207  /*err =*/ sqlite3_exec(database, "select param_value from parameters where param_name = 'version';", check_tables_callback, &format, NULL);
208 
209  /* Safety check. */
211  cf_log(llevError, " [%s] Logger database format (%d) is newer than supported (%d) by this binary!. Won't log.\n", PLUGIN_NAME, format, CFLOGGER_CURRENT_FORMAT);
212  /* This will disable using the db since do_sql() checks if database is
213  * NULL.
214  */
215  sqlite3_close(database);
216  database = NULL;
217  }
218 
219  /* Check if we need to upgrade/create database. */
220  if (format < 1) {
221  cf_log(llevDebug, " [%s] Creating logger database schema (format 1).\n", PLUGIN_NAME);
222  if (do_sql("BEGIN EXCLUSIVE TRANSACTION;") != SQLITE_OK) {
223  cf_log(llevError, " [%s] Logger database format update failed! Couldn't acquire exclusive lock to database when upgrading from format %d to format %d!. Won't log.\n", PLUGIN_NAME, format, CFLOGGER_CURRENT_FORMAT);
224  sqlite3_close(database);
225  database = NULL;
226  return;
227  }
228  DO_OR_ROLLBACK("create table living(liv_id integer primary key autoincrement, liv_name text, liv_is_player integer, liv_level integer);");
229  DO_OR_ROLLBACK("create table region(reg_id integer primary key autoincrement, reg_name text);");
230  DO_OR_ROLLBACK("create table map(map_id integer primary key autoincrement, map_path text, map_reg_id integer);");
231  DO_OR_ROLLBACK("create table time(time_real integer, time_ingame text);");
232 
233  DO_OR_ROLLBACK("create table living_event(le_liv_id integer, le_time integer, le_code integer, le_map_id integer);");
234  DO_OR_ROLLBACK("create table map_event(me_map_id integer, me_time integer, me_code integer, me_living_id integer);");
235  DO_OR_ROLLBACK("create table kill_event(ke_time integer, ke_victim_id integer, ke_victim_level integer, ke_map_id integer , ke_killer_id integer, ke_killer_level integer);");
236 
237  DO_OR_ROLLBACK("create table parameters(param_name text, param_value text);");
238  DO_OR_ROLLBACK("insert into parameters values( 'version', '1' );");
239  do_sql("COMMIT TRANSACTION;");
240  }
241 
242  /* Must be able to handle update from format 1. If we are creating a new
243  * database, format 1 is still created first, then updated.
244  *
245  * This way is simpler than having to create two ways to make a format 2 db.
246  */
247  if (format < 2) {
248  cf_log(llevDebug, " [%s] Upgrading logger database schema (to format 2).\n", PLUGIN_NAME);
249  if (do_sql("BEGIN EXCLUSIVE TRANSACTION;") != SQLITE_OK) {
250  cf_log(llevError, " [%s] Logger database format update failed! Couldn't acquire exclusive lock to database when upgrading from format %d to format %d!. Won't log.\n", PLUGIN_NAME, format, CFLOGGER_CURRENT_FORMAT);
251  sqlite3_close(database);
252  database = NULL;
253  return;
254  }
255  /* Update schema for various tables. Why so complex? Because ALTER TABLE
256  * can't add the "primary key" bit or other constraints...
257  */
258  UPDATE_OR_ROLLBACK("living", "liv_id INTEGER PRIMARY KEY AUTOINCREMENT, liv_name TEXT NOT NULL, liv_is_player INTEGER NOT NULL, liv_level INTEGER NOT NULL", "*");
259  UPDATE_OR_ROLLBACK("region", "reg_id INTEGER PRIMARY KEY AUTOINCREMENT, reg_name TEXT UNIQUE NOT NULL", "*");
260  UPDATE_OR_ROLLBACK("map", "map_id INTEGER PRIMARY KEY AUTOINCREMENT, map_path TEXT NOT NULL, map_reg_id INTEGER NOT NULL, CONSTRAINT map_path_reg_id UNIQUE(map_path, map_reg_id)", "*");
261 #if 0
262  /* Turned out this was incorrect. And version 1 -> 3 directly works for this. */
263  UPDATE_OR_ROLLBACK("time", "time_real INTEGER PRIMARY KEY, time_ingame TEXT UNIQUE NOT NULL");
264 #endif
265  UPDATE_OR_ROLLBACK("living_event", "le_liv_id INTEGER NOT NULL, le_time INTEGER NOT NULL, le_code INTEGER NOT NULL, le_map_id INTEGER NOT NULL", "*");
266  UPDATE_OR_ROLLBACK("map_event", "me_map_id INTEGER NOT NULL, me_time INTEGER NOT NULL, me_code INTEGER NOT NULL, me_living_id INTEGER NOT NULL", "*");
267  UPDATE_OR_ROLLBACK("kill_event", "ke_time INTEGER NOT NULL, ke_victim_id INTEGER NOT NULL, ke_victim_level INTEGER NOT NULL, ke_map_id INTEGER NOT NULL, ke_killer_id INTEGER NOT NULL, ke_killer_level INTEGER NOT NULL", "*");
268 
269  /* Handle changed parameters table format: */
270  /* Due to backward compatiblity "primary key" in SQLite doesn't imply
271  * "not null" (http://www.sqlite.org/lang_createtable.html), unless it
272  * is "integer primary key".
273  *
274  * We don't need to save anything stored in this in format 1, it was
275  * only used for storing what format was used.
276  */
277  DO_OR_ROLLBACK("DROP TABLE parameters;");
278  DO_OR_ROLLBACK("CREATE TABLE parameters(param_name TEXT NOT NULL PRIMARY KEY, param_value TEXT);");
279  DO_OR_ROLLBACK("INSERT INTO parameters (param_name, param_value) VALUES( 'version', '2' );");
280 
281  /* Create various indexes. */
282  DO_OR_ROLLBACK("CREATE INDEX living_name_player_level ON living(liv_name,liv_is_player,liv_level);");
283 
284  /* Newspaper module could make use of some indexes too: */
285  DO_OR_ROLLBACK("CREATE INDEX kill_event_time ON kill_event(ke_time);");
286  DO_OR_ROLLBACK("CREATE INDEX map_reg_id ON map(map_reg_id);");
287 
288  /* Finally commit the transaction. */
289  do_sql("COMMIT TRANSACTION;");
290  }
291 
292  if (format < 3) {
293  cf_log(llevDebug, " [%s] Upgrading logger database schema (to format 3).\n", PLUGIN_NAME);
294  if (do_sql("BEGIN EXCLUSIVE TRANSACTION;") != SQLITE_OK) {
295  cf_log(llevError, " [%s] Logger database format update failed! Couldn't acquire exclusive lock to database when upgrading from format %d to format %d!. Won't log.\n", PLUGIN_NAME, format, CFLOGGER_CURRENT_FORMAT);
296  sqlite3_close(database);
297  database = NULL;
298  return;
299  }
300  UPDATE_OR_ROLLBACK("time", "time_ingame TEXT NOT NULL PRIMARY KEY, time_real INTEGER NOT NULL", "time_ingame, time_real");
301  DO_OR_ROLLBACK("UPDATE parameters SET param_value = '3' WHERE param_name = 'version';");
302  do_sql("COMMIT TRANSACTION;");
303  /* After all these changes better vacuum... The tables could have been
304  * huge, and since we recreated several of them above there could be a
305  * lot of wasted space.
306  */
307  do_sql("VACUUM;");
308  }
309 }
310 
326 static int get_living_id(object *living) {
327  char **line;
328  char *sql;
329  int nrow, ncolumn, id;
330 
331  if (living->type == PLAYER)
332  sql = sqlite3_mprintf("select liv_id from living where liv_name='%q' and liv_is_player = 1", living->name);
333  else
334  sql = sqlite3_mprintf("select liv_id from living where liv_name='%q' and liv_is_player = 0 and liv_level = %d", living->name, living->level);
335  sqlite3_get_table(database, sql, &line, &nrow, &ncolumn, NULL);
336 
337  if (nrow > 0)
338  id = atoi(line[ncolumn]);
339  else {
340  sqlite3_free(sql);
341  sql = sqlite3_mprintf("insert into living(liv_name, liv_is_player, liv_level) values('%q', %d, %d)", living->name, living->type == PLAYER ? 1 : 0, living->level);
342  do_sql(sql);
343  id = sqlite3_last_insert_rowid(database);
344  }
345  sqlite3_free(sql);
346  sqlite3_free_table(line);
347  return id;
348 }
349 
360 static int get_region_id(region *reg) {
361  char **line;
362  char *sql;
363  int nrow, ncolumn, id;
364 
365  if (!reg)
366  return 0;
367 
368  sql = sqlite3_mprintf("select reg_id from region where reg_name='%q'", reg->name);
369  sqlite3_get_table(database, sql, &line, &nrow, &ncolumn, NULL);
370 
371  if (nrow > 0)
372  id = atoi(line[ncolumn]);
373  else {
374  sqlite3_free(sql);
375  sql = sqlite3_mprintf("insert into region(reg_name) values( '%q' )", reg->name);
376  do_sql(sql);
377  id = sqlite3_last_insert_rowid(database);
378  }
379  sqlite3_free(sql);
380  sqlite3_free_table(line);
381  return id;
382 }
383 
396 static int get_map_id(mapstruct *map) {
397  char **line;
398  char *sql;
399  int nrow, ncolumn, id, reg_id;
400  const char *path = map->path;
401 
402  if (strncmp(path, "/random/", 7) == 0)
403  path = "/random/";
404 
405  reg_id = get_region_id(map->region);
406  sql = sqlite3_mprintf("select map_id from map where map_path='%q' and map_reg_id = %d", path, reg_id);
407  sqlite3_get_table(database, sql, &line, &nrow, &ncolumn, NULL);
408 
409  if (nrow > 0)
410  id = atoi(line[ncolumn]);
411  else {
412  sqlite3_free(sql);
413  sql = sqlite3_mprintf("insert into map(map_path, map_reg_id) values( '%q', %d)", path, reg_id);
414  do_sql(sql);
415  id = sqlite3_last_insert_rowid(database);
416  }
417  sqlite3_free(sql);
418  sqlite3_free_table(line);
419 
420  return id;
421 }
422 
429 static int store_time(void) {
430  char **line;
431  char *sql;
432  int nrow, ncolumn;
433  char date[50];
434  time_t now;
435  timeofday_t tod;
436 
437  cf_get_time(&tod);
438  now = time(NULL);
439 
440  if (tod.day == last_stored_day)
441  return 0;
442  last_stored_day = tod.day;
443 
444  snprintf(date, 50, "%10d-%2d-%2d %2d:%2d", tod.year, tod.month, tod.day, tod.hour, tod.minute);
445 
446  sql = sqlite3_mprintf("select * from time where time_ingame='%q'", date);
447  sqlite3_get_table(database, sql, &line, &nrow, &ncolumn, NULL);
448  sqlite3_free(sql);
449  sqlite3_free_table(line);
450  if (nrow > 0)
451  return 0;
452 
453  sql = sqlite3_mprintf("insert into time (time_ingame, time_real) values( '%s', %d )", date, now);
454  do_sql(sql);
455  sqlite3_free(sql);
456  return 1;
457 }
458 
467 static void add_player_event(object *pl, int event_code) {
468  int map_id = 0;
469  char *sql;
470 
471  if (pl == NULL)
472  return;
473 
474  int id = get_living_id(pl);
475  if (pl->map)
476  map_id = get_map_id(pl->map);
477 
478  sql = sqlite3_mprintf("insert into living_event values( %d, %d, %d, %d)", id, time(NULL), event_code, map_id);
479  do_sql(sql);
480  sqlite3_free(sql);
481 }
482 
493 static void add_map_event(mapstruct *map, int event_code, object *pl) {
494  int mapid;
495  int playerid = 0;
496  char *sql;
497 
498  if (pl && pl->type == PLAYER)
499  playerid = get_living_id(pl);
500 
501  mapid = get_map_id(map);
502  sql = sqlite3_mprintf("insert into map_event values( %d, %d, %d, %d)", mapid, time(NULL), event_code, playerid);
503  do_sql(sql);
504  sqlite3_free(sql);
505 }
506 
517 static void add_death(object *victim, object *killer) {
518  int vid, kid, map_id;
519  char *sql;
520 
521  if (!victim || !killer)
522  return;
523  if (victim->type != PLAYER && killer->type != PLAYER) {
524  /* Killer might be a bullet, which might be owned by the player. */
526  if (owner != NULL && owner->type == PLAYER)
527  killer = owner;
528  else
529  return;
530  }
531 
532  vid = get_living_id(victim);
533  kid = get_living_id(killer);
534  map_id = get_map_id(victim->map);
535  sql = sqlite3_mprintf("insert into kill_event values( %d, %d, %d, %d, %d, %d)", time(NULL), vid, victim->level, map_id, kid, killer->level);
536  do_sql(sql);
537  sqlite3_free(sql);
538 }
539 
550 extern "C" int initPlugin(const char *iversion, f_plug_api gethooksptr) {
551  cf_init_plugin(gethooksptr);
552  cf_log(llevInfo, "%s init\n", PLUGIN_VERSION);
553  return 0;
554 }
555 
566 extern "C" void *getPluginProperty(int *type, ...) {
567  va_list args;
568  const char *propname;
569  char *buf;
570  int size;
571 
572  va_start(args, type);
573  propname = va_arg(args, const char *);
574 
575  if (!strcmp(propname, "Identification")) {
576  buf = va_arg(args, char *);
577  size = va_arg(args, int);
578  va_end(args);
579  snprintf(buf, size, PLUGIN_NAME);
580  return NULL;
581  } else if (!strcmp(propname, "FullName")) {
582  buf = va_arg(args, char *);
583  size = va_arg(args, int);
584  va_end(args);
585  snprintf(buf, size, PLUGIN_VERSION);
586  return NULL;
587  }
588  va_end(args);
589  return NULL;
590 }
591 
602 extern "C" int cflogger_runPluginCommand(object *op, char *params) {
603  return -1;
604 }
605 
614 extern "C" int eventListener(int *type, ...) {
615  return 0;
616 }
617 
626 extern "C" int cflogger_globalEventListener(int *type, ...) {
627  va_list args;
628  int rv = 0;
629  player *pl;
630  object *op/*, *op2*/;
631  int event_code;
632  mapstruct *map;
633 
634  va_start(args, type);
635  event_code = va_arg(args, int);
636 
637  switch (event_code) {
638  case EVENT_BORN:
639  case EVENT_REMOVE:
640  case EVENT_MUZZLE:
641  case EVENT_KICK:
642  op = va_arg(args, object *);
643  add_player_event(op, event_code);
644  break;
645 
646  case EVENT_PLAYER_DEATH:
647  op = va_arg(args, object *);
648  /*op2 =*/ va_arg(args, object *);
649  add_player_event(op, event_code);
650  break;
651 
652  case EVENT_LOGIN:
653  case EVENT_LOGOUT:
654  pl = va_arg(args, player *);
655  add_player_event(pl->ob, event_code);
656  break;
657 
658  case EVENT_MAPENTER:
659  case EVENT_MAPLEAVE:
660  op = va_arg(args, object *);
661  map = va_arg(args, mapstruct *);
662  add_map_event(map, event_code, op);
663  break;
664 
665  case EVENT_MAPLOAD:
666  case EVENT_MAPUNLOAD:
667  case EVENT_MAPRESET:
668  map = va_arg(args, mapstruct *);
669  add_map_event(map, event_code, NULL);
670  break;
671 
672  case EVENT_GKILL: {
673  object *killer;
674  op = va_arg(args, object *);
675  killer = va_arg(args, object *);
676  add_death(op, killer);
677  }
678  break;
679 
680  case EVENT_CLOCK:
681  store_time();
682  break;
683  }
684  va_end(args);
685 
686  return rv;
687 }
688 
697 extern "C" int postInitPlugin(void) {
698  char path[500];
699  const char *dir;
700 
701  cf_log(llevInfo, "%s post init\n", PLUGIN_VERSION);
702 
703  dir = cf_get_directory(4);
704  snprintf(path, sizeof(path), "%s/cflogger.db", dir);
705  cf_log(llevDebug, " [%s] database file: %s\n", PLUGIN_NAME, path);
706 
707  if (sqlite3_open(path, &database) != SQLITE_OK) {
708  cf_log(llevError, " [%s] database error!\n", PLUGIN_NAME);
709  sqlite3_close(database);
710  database = NULL;
711  return 0;
712  }
713 
714  check_tables();
715 
716  store_time();
717 
723 
725 
731 
734 
736 
737  return 0;
738 }
739 
748 extern "C" int closePlugin(void) {
749  cf_log(llevInfo, "%s closing.\n", PLUGIN_VERSION);
750  if (database) {
751  sqlite3_close(database);
752  database = NULL;
753  }
754  return 0;
755 }
PLAYER
@ PLAYER
Definition: object.h:112
cf_log
void cf_log(LogLevel logLevel, const char *format,...)
Definition: plugin_common.cpp:1522
do_sql
static int do_sql(const char *sql)
Definition: cflogger.cpp:103
line
Install Bug reporting Credits so make sure you have version or later There are files involved in the automatic convert convertall and filelist py GuildList has the list of guilds for the server GuildLocations is what is used by the install script for setting up the maps It has columns in the first is the name of the no spaces The second is the region of the the third is the destination folder for the the fourth is the exit the fifth and sixth are the x and y coords within the exit the seventh eighth and ninth are the exit location for the storage hall If field seven is then it uses the same exit map as for the guild hall itself filelist py has a list of which files to process for each guild hall convert py takes all the files in filelist py and customises them to the specific guild then outputs them into a in the same order that they are listed in GuildLocations convertall py reads the lines from GuildLocations and runs line by line
Definition: README.txt:12
cf_get_directory
const char * cf_get_directory(int id)
Definition: plugin_common.cpp:1130
llevError
@ llevError
Definition: logger.h:11
check_tables_callback
static int check_tables_callback(void *param, int argc, char **argv, char **azColName)
Definition: cflogger.cpp:81
postInitPlugin
int postInitPlugin(void)
Definition: cflogger.cpp:697
player
Definition: player.h:105
timeofday_t::year
int year
Definition: tod.h:39
update_table_format
static int update_table_format(const char *table, const char *newschema, const char *select_columns)
Definition: cflogger.cpp:144
cf_object_get_object_property
object * cf_object_get_object_property(object *op, int propcode)
Definition: plugin_common.cpp:365
UPDATE_OR_ROLLBACK
#define UPDATE_OR_ROLLBACK(tbl, newschema, select_columns)
Definition: cflogger.cpp:190
send.date
date
Definition: send.py:29
add_map_event
static void add_map_event(mapstruct *map, int event_code, object *pl)
Definition: cflogger.cpp:493
get_map_id
static int get_map_id(mapstruct *map)
Definition: cflogger.cpp:396
SVN_REV
#define SVN_REV
Definition: svnversion.h:2
get_region_id
static int get_region_id(region *reg)
Definition: cflogger.cpp:360
timeofday_t
Definition: tod.h:38
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
EVENT_MAPLOAD
#define EVENT_MAPLOAD
Definition: events.h:48
EVENT_LOGOUT
#define EVENT_LOGOUT
Definition: events.h:45
closePlugin
int closePlugin(void)
Definition: cflogger.cpp:748
getPluginProperty
void * getPluginProperty(int *type,...)
Definition: cflogger.cpp:566
region::name
char * name
Definition: map.h:274
buf
StringBuffer * buf
Definition: readable.cpp:1552
timeofday_t::day
int day
Definition: tod.h:41
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:44
disinfect.map
map
Definition: disinfect.py:4
EVENT_CLOCK
#define EVENT_CLOCK
Definition: events.h:40
make_face_from_files.args
args
Definition: make_face_from_files.py:37
cflogger_runPluginCommand
int cflogger_runPluginCommand(object *op, char *params)
Definition: cflogger.cpp:602
CF_PLUGIN
#define CF_PLUGIN
Definition: plugin_common.h:38
f_plug_api
void(* f_plug_api)(int *type,...)
Definition: plugin.h:79
EVENT_MAPENTER
#define EVENT_MAPENTER
Definition: events.h:46
cf_init_plugin
int cf_init_plugin(f_plug_api getHooks)
Definition: plugin_common.cpp:146
PLUGIN_NAME
#define PLUGIN_NAME
Definition: cfanim.h:32
EVENT_MAPRESET
#define EVENT_MAPRESET
Definition: events.h:50
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
EVENT_BORN
#define EVENT_BORN
Definition: events.h:39
object::type
uint8_t type
Definition: object.h:348
EVENT_MAPUNLOAD
#define EVENT_MAPUNLOAD
Definition: events.h:51
cflogger_globalEventListener
int cflogger_globalEventListener(int *type,...)
Definition: cflogger.cpp:626
CFLOGGER_CURRENT_FORMAT
#define CFLOGGER_CURRENT_FORMAT
Definition: cflogger.cpp:58
add_player_event
static void add_player_event(object *pl, int event_code)
Definition: cflogger.cpp:467
store_time
static int store_time(void)
Definition: cflogger.cpp:429
CFAPI_OBJECT_PROP_OWNER
#define CFAPI_OBJECT_PROP_OWNER
Definition: plugin.h:191
timeofday_t::month
int month
Definition: tod.h:40
living
Definition: living.h:35
eventListener
int eventListener(int *type,...)
Definition: cflogger.cpp:614
last_stored_day
static int last_stored_day
Definition: cflogger.cpp:64
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
EVENT_PLAYER_DEATH
#define EVENT_PLAYER_DEATH
Definition: events.h:53
PLUGIN_VERSION
#define PLUGIN_VERSION
Definition: cfanim.h:33
region
Definition: map.h:273
SvnRevPlugin
CF_PLUGIN char SvnRevPlugin[]
Definition: cflogger.cpp:55
cf_system_register_global_event
void cf_system_register_global_event(int event, const char *name, f_plug_event hook)
Definition: plugin_common.cpp:1102
llevInfo
@ llevInfo
Definition: logger.h:12
EVENT_MUZZLE
#define EVENT_MUZZLE
Definition: events.h:52
cflogger_proto.h
timeofday_t::minute
int minute
Definition: tod.h:44
reputation.victim
victim
Definition: reputation.py:14
add_death
static void add_death(object *victim, object *killer)
Definition: cflogger.cpp:517
mapstruct
Definition: map.h:314
give.op
op
Definition: give.py:33
database
static sqlite3 * database
Definition: cflogger.cpp:61
format
Python Guilds Quick outline Add a guild(mapmakers) this is still a problem *after dropping the token to gain access to the stove a woodfloor now appears which is Toolshed Token(found in Guild_HQ) *Note also have multiple gates in place to protect players and items from the mana explosion drop x for Jewelers room *Jewelers room works just need to determine what x is drop x for Thaumaturgy room *Thaumaturgy room works just need to determine what x is drop gold dropping the Firestar named fearless allows access to but I suspect that the drop location of the chest is not as intended because the player is in the way once you enter the chest the exit back to the basement is things such as the message et al reside on teleporters which then transport items to the map as they are when the map is already purchased items reappear in that area From my this does not cause any problems at the moment But this should be corrected fixed Major it s now possible to buy guilds Ryo Update Uploaded guild package to CVS Changes the cauldrons and the charging room I spent a while agonizing over They were natural guild enhancements but much too much value for any reasonable expense to buy them Then I thought that they should be pay access but at a greatly reduced rate SO when you buy a forge or whatever for your guild it is available on a perplayer daily rate but it will be accessable for testing and to DMs to play with Like I said lots still to do with the especially comingt up with quest items for buying things like the new workshops and stuff One of the things I would like some input on would be proposals for additional fields for either the guildhouses or guild datafiles to play with Currently the Guildhouse but there is no reason we can t have more than one measure of a guild perhaps have dues relate to Dues and use points for some other suspended or inactive or when a guild is founded inactive active Guilds have the format
Definition: README.txt:140
EVENT_MAPLEAVE
#define EVENT_MAPLEAVE
Definition: events.h:47
timeofday_t::hour
int hour
Definition: tod.h:43
roll-o-matic.params
params
Definition: roll-o-matic.py:193
EVENT_REMOVE
#define EVENT_REMOVE
Definition: events.h:54
get_living_id
static int get_living_id(object *living)
Definition: cflogger.cpp:326
DO_OR_ROLLBACK
#define DO_OR_ROLLBACK(sqlstring)
Definition: cflogger.cpp:181
check_tables
static void check_tables(void)
Definition: cflogger.cpp:202
now
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For now
Definition: protocol.txt:71
param
No space after the left no space before the right paren Comma right after the formal param
Definition: style-guide.txt:215
svnversion.h
reputation.killer
def killer
Definition: reputation.py:13
cflogger.h
initPlugin
int initPlugin(const char *iversion, f_plug_api gethooksptr)
Definition: cflogger.cpp:550
EVENT_GKILL
#define EVENT_GKILL
Definition: events.h:42
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
EVENT_KICK
#define EVENT_KICK
Definition: events.h:43
cf_get_time
void cf_get_time(timeofday_t *tod)
Definition: plugin_common.cpp:1549
llevDebug
@ llevDebug
Definition: logger.h:13
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
diamondslots.id
id
Definition: diamondslots.py:53