Go to the documentation of this file.
58 #define CFLOGGER_CURRENT_FORMAT 3
110 err = sqlite3_exec(
database, sql, NULL, NULL, &
msg);
111 if (err != SQLITE_OK) {
145 const char *select_columns) {
149 sql = sqlite3_mprintf(
"ALTER TABLE %s RENAME TO %s_old;", table, table);
152 if (err != SQLITE_OK)
155 sql = sqlite3_mprintf(
"CREATE TABLE %s(%s);", table, newschema);
158 if (err != SQLITE_OK)
161 sql = sqlite3_mprintf(
"INSERT INTO %s SELECT %s FROM %s_old;",
162 table, select_columns, table);
165 if (err != SQLITE_OK)
168 sql = sqlite3_mprintf(
"DROP TABLE %s_old;", table, table);
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); \
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); \
222 if (
do_sql(
"BEGIN EXCLUSIVE TRANSACTION;") != SQLITE_OK) {
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);");
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);");
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;");
249 if (
do_sql(
"BEGIN EXCLUSIVE TRANSACTION;") != SQLITE_OK) {
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)",
"*");
263 UPDATE_OR_ROLLBACK(
"time",
"time_real INTEGER PRIMARY KEY, time_ingame TEXT UNIQUE NOT NULL");
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",
"*");
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' );");
282 DO_OR_ROLLBACK(
"CREATE INDEX living_name_player_level ON living(liv_name,liv_is_player,liv_level);");
285 DO_OR_ROLLBACK(
"CREATE INDEX kill_event_time ON kill_event(ke_time);");
289 do_sql(
"COMMIT TRANSACTION;");
294 if (
do_sql(
"BEGIN EXCLUSIVE TRANSACTION;") != SQLITE_OK) {
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;");
329 int nrow, ncolumn,
id;
332 sql = sqlite3_mprintf(
"select liv_id from living where liv_name='%q' and liv_is_player = 1",
living->name);
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);
338 id = atoi(
line[ncolumn]);
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);
343 id = sqlite3_last_insert_rowid(
database);
346 sqlite3_free_table(
line);
363 int nrow, ncolumn,
id;
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);
372 id = atoi(
line[ncolumn]);
375 sql = sqlite3_mprintf(
"insert into region(reg_name) values( '%q' )", reg->
name);
377 id = sqlite3_last_insert_rowid(
database);
380 sqlite3_free_table(
line);
399 int nrow, ncolumn,
id, reg_id;
402 if (strncmp(
path,
"/random/", 7) == 0)
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);
410 id = atoi(
line[ncolumn]);
413 sql = sqlite3_mprintf(
"insert into map(map_path, map_reg_id) values( '%q', %d)",
path, reg_id);
415 id = sqlite3_last_insert_rowid(
database);
418 sqlite3_free_table(
line);
446 sql = sqlite3_mprintf(
"select * from time where time_ingame='%q'",
date);
447 sqlite3_get_table(
database, sql, &
line, &nrow, &ncolumn, NULL);
449 sqlite3_free_table(
line);
453 sql = sqlite3_mprintf(
"insert into time (time_ingame, time_real) values( '%s', %d )",
date,
now);
478 sql = sqlite3_mprintf(
"insert into living_event values( %d, %d, %d, %d)",
id,
time(NULL), event_code, map_id);
502 sql = sqlite3_mprintf(
"insert into map_event values( %d, %d, %d, %d)", mapid,
time(NULL), event_code, playerid);
518 int vid, kid, map_id;
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);
568 const char *propname;
573 propname = va_arg(
args,
const char *);
575 if (!strcmp(propname,
"Identification")) {
577 size = va_arg(
args,
int);
581 }
else if (!strcmp(propname,
"FullName")) {
583 size = va_arg(
args,
int);
635 event_code = va_arg(
args,
int);
637 switch (event_code) {
642 op = va_arg(
args,
object *);
647 op = va_arg(
args,
object *);
648 va_arg(
args,
object *);
660 op = va_arg(
args,
object *);
674 op = va_arg(
args,
object *);
704 snprintf(
path,
sizeof(
path),
"%s/cflogger.db", dir);
void cf_log(LogLevel logLevel, const char *format,...)
static int do_sql(const char *sql)
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
const char * cf_get_directory(int id)
static int check_tables_callback(void *param, int argc, char **argv, char **azColName)
static int update_table_format(const char *table, const char *newschema, const char *select_columns)
object * cf_object_get_object_property(object *op, int propcode)
#define UPDATE_OR_ROLLBACK(tbl, newschema, select_columns)
static void add_map_event(mapstruct *map, int event_code, object *pl)
static int get_map_id(mapstruct *map)
static int get_region_id(region *reg)
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
void * getPluginProperty(int *type,...)
int cflogger_runPluginCommand(object *op, char *params)
void(* f_plug_api)(int *type,...)
int cf_init_plugin(f_plug_api getHooks)
int cflogger_globalEventListener(int *type,...)
#define CFLOGGER_CURRENT_FORMAT
static void add_player_event(object *pl, int event_code)
static int store_time(void)
#define CFAPI_OBJECT_PROP_OWNER
int eventListener(int *type,...)
static int last_stored_day
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
#define EVENT_PLAYER_DEATH
CF_PLUGIN char SvnRevPlugin[]
void cf_system_register_global_event(int event, const char *name, f_plug_event hook)
static void add_death(object *victim, object *killer)
static sqlite3 * database
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
static int get_living_id(object *living)
#define DO_OR_ROLLBACK(sqlstring)
static void check_tables(void)
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
No space after the left no space before the right paren Comma right after the formal param
int initPlugin(const char *iversion, f_plug_api gethooksptr)
void cf_get_time(timeofday_t *tod)