359 lines
9.1 KiB
C++
359 lines
9.1 KiB
C++
// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
|
|
// For more information, see LICENCE in the main folder
|
|
|
|
#include "mapreg.hpp"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "../common/cbasetypes.hpp"
|
|
#include "../common/db.hpp"
|
|
#include "../common/ers.hpp"
|
|
#include "../common/malloc.hpp"
|
|
#include "../common/showmsg.hpp"
|
|
#include "../common/sql.hpp"
|
|
#include "../common/strlib.hpp"
|
|
#include "../common/timer.hpp"
|
|
|
|
#include "map.hpp" // mmysql_handle
|
|
#include "script.hpp"
|
|
|
|
static struct eri *mapreg_ers;
|
|
|
|
bool skip_insert = false;
|
|
|
|
static char mapreg_table[32] = "mapreg";
|
|
static bool mapreg_dirty = false; // Whether there are modified regs to be saved
|
|
struct reg_db regs;
|
|
|
|
#define MAPREG_AUTOSAVE_INTERVAL (300*1000)
|
|
|
|
|
|
/**
|
|
* Looks up the value of an integer variable using its uid.
|
|
*
|
|
* @param uid: variable's unique identifier.
|
|
* @return: variable's integer value
|
|
*/
|
|
int mapreg_readreg(int64 uid)
|
|
{
|
|
struct mapreg_save *m = (struct mapreg_save *)i64db_get(regs.vars, uid);
|
|
return m ? m->u.i : 0;
|
|
}
|
|
|
|
/**
|
|
* Looks up the value of a string variable using its uid.
|
|
*
|
|
* @param uid: variable's unique identifier
|
|
* @return: variable's string value
|
|
*/
|
|
char* mapreg_readregstr(int64 uid)
|
|
{
|
|
struct mapreg_save *m = (struct mapreg_save *)i64db_get(regs.vars, uid);
|
|
return m ? m->u.str : NULL;
|
|
}
|
|
|
|
/**
|
|
* Modifies the value of an integer variable.
|
|
*
|
|
* @param uid: variable's unique identifier
|
|
* @param val new value
|
|
* @return: true value was successfully set
|
|
*/
|
|
bool mapreg_setreg(int64 uid, int val)
|
|
{
|
|
struct mapreg_save *m;
|
|
int num = script_getvarid(uid);
|
|
unsigned int i = script_getvaridx(uid);
|
|
const char* name = get_str(num);
|
|
|
|
if (val != 0) {
|
|
if ((m = static_cast<mapreg_save *>(i64db_get(regs.vars, uid)))) {
|
|
m->u.i = val;
|
|
if (name[1] != '@') {
|
|
m->save = true;
|
|
mapreg_dirty = true;
|
|
}
|
|
} else {
|
|
if (i)
|
|
script_array_update(®s, uid, false);
|
|
|
|
m = ers_alloc(mapreg_ers, struct mapreg_save);
|
|
|
|
m->u.i = val;
|
|
m->uid = uid;
|
|
m->save = false;
|
|
m->is_string = false;
|
|
|
|
if (name[1] != '@' && !skip_insert) {// write new variable to database
|
|
char esc_name[32 * 2 + 1];
|
|
Sql_EscapeStringLen(mmysql_handle, esc_name, name, strnlen(name, 32));
|
|
if (SQL_ERROR == Sql_Query(mmysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%d')", mapreg_table, esc_name, i, val))
|
|
Sql_ShowDebug(mmysql_handle);
|
|
}
|
|
i64db_put(regs.vars, uid, m);
|
|
}
|
|
} else { // val == 0
|
|
if (i)
|
|
script_array_update(®s, uid, true);
|
|
if ((m = static_cast<mapreg_save *>(i64db_get(regs.vars, uid)))) {
|
|
ers_free(mapreg_ers, m);
|
|
}
|
|
i64db_remove(regs.vars, uid);
|
|
|
|
if (name[1] != '@') {// Remove from database because it is unused.
|
|
char esc_name[32 * 2 + 1];
|
|
Sql_EscapeStringLen(mmysql_handle, esc_name, name, strnlen(name, 32));
|
|
if (SQL_ERROR == Sql_Query(mmysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg_table, esc_name, i))
|
|
Sql_ShowDebug(mmysql_handle);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Modifies the value of a string variable.
|
|
*
|
|
* @param uid: variable's unique identifier
|
|
* @param str: new value
|
|
* @return: true value was successfully set
|
|
*/
|
|
bool mapreg_setregstr(int64 uid, const char* str)
|
|
{
|
|
struct mapreg_save *m;
|
|
int num = script_getvarid(uid);
|
|
unsigned int i = script_getvaridx(uid);
|
|
const char* name = get_str(num);
|
|
|
|
if (str == NULL || *str == 0) {
|
|
if (i)
|
|
script_array_update(®s, uid, true);
|
|
if (name[1] != '@') {
|
|
char esc_name[32 * 2 + 1];
|
|
Sql_EscapeStringLen(mmysql_handle, esc_name, name, strnlen(name, 32));
|
|
if (SQL_ERROR == Sql_Query(mmysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg_table, esc_name, i))
|
|
Sql_ShowDebug(mmysql_handle);
|
|
}
|
|
if ((m = static_cast<mapreg_save *>(i64db_get(regs.vars, uid)))) {
|
|
if (m->u.str != NULL)
|
|
aFree(m->u.str);
|
|
ers_free(mapreg_ers, m);
|
|
}
|
|
i64db_remove(regs.vars, uid);
|
|
} else {
|
|
if ((m = static_cast<mapreg_save *>(i64db_get(regs.vars, uid)))) {
|
|
if (m->u.str != NULL)
|
|
aFree(m->u.str);
|
|
m->u.str = aStrdup(str);
|
|
if (name[1] != '@') {
|
|
mapreg_dirty = true;
|
|
m->save = true;
|
|
}
|
|
} else {
|
|
if (i)
|
|
script_array_update(®s, uid, false);
|
|
|
|
m = ers_alloc(mapreg_ers, struct mapreg_save);
|
|
|
|
m->uid = uid;
|
|
m->u.str = aStrdup(str);
|
|
m->save = false;
|
|
m->is_string = true;
|
|
|
|
if (name[1] != '@' && !skip_insert) { //put returned null, so we must insert.
|
|
char esc_name[32 * 2 + 1];
|
|
char esc_str[255 * 2 + 1];
|
|
Sql_EscapeStringLen(mmysql_handle, esc_name, name, strnlen(name, 32));
|
|
Sql_EscapeStringLen(mmysql_handle, esc_str, str, strnlen(str, 255));
|
|
if (SQL_ERROR == Sql_Query(mmysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%s')", mapreg_table, esc_name, i, esc_str))
|
|
Sql_ShowDebug(mmysql_handle);
|
|
}
|
|
i64db_put(regs.vars, uid, m);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Loads permanent variables from database.
|
|
*/
|
|
static void script_load_mapreg(void)
|
|
{
|
|
/*
|
|
0 1 2
|
|
+-------------------------+
|
|
| varname | index | value |
|
|
+-------------------------+
|
|
*/
|
|
SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
|
|
char varname[32+1];
|
|
int index;
|
|
char value[255+1];
|
|
uint32 length;
|
|
|
|
if ( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `varname`, `index`, `value` FROM `%s`", mapreg_table)
|
|
|| SQL_ERROR == SqlStmt_Execute(stmt)
|
|
) {
|
|
SqlStmt_ShowDebug(stmt);
|
|
SqlStmt_Free(stmt);
|
|
return;
|
|
}
|
|
|
|
skip_insert = true;
|
|
|
|
SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &varname[0], sizeof(varname), &length, NULL);
|
|
SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &index, 0, NULL, NULL);
|
|
SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &value[0], sizeof(value), NULL, NULL);
|
|
|
|
while ( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
|
|
int s = add_str(varname);
|
|
int i = index;
|
|
|
|
if( i64db_exists(regs.vars, reference_uid(s, i)) ) {
|
|
ShowWarning("load_mapreg: duplicate! '%s' => '%s' skipping...\n",varname,value);
|
|
continue;
|
|
}
|
|
if( varname[length-1] == '$' ) {
|
|
mapreg_setregstr(reference_uid(s, i), value);
|
|
} else {
|
|
mapreg_setreg(reference_uid(s, i), atoi(value));
|
|
}
|
|
}
|
|
|
|
SqlStmt_Free(stmt);
|
|
|
|
skip_insert = false;
|
|
mapreg_dirty = false;
|
|
}
|
|
|
|
/**
|
|
* Saves permanent variables to database.
|
|
*/
|
|
static void script_save_mapreg(void)
|
|
{
|
|
if (mapreg_dirty) {
|
|
DBIterator *iter = db_iterator(regs.vars);
|
|
struct mapreg_save *m;
|
|
for (m = static_cast<mapreg_save *>(dbi_first(iter)); dbi_exists(iter); m = static_cast<mapreg_save *>(dbi_next(iter))) {
|
|
if (m->save) {
|
|
int num = script_getvarid(m->uid);
|
|
int i = script_getvaridx(m->uid);
|
|
const char* name = get_str(num);
|
|
if (!m->is_string) {
|
|
char esc_name[32 * 2 + 1];
|
|
Sql_EscapeStringLen(mmysql_handle, esc_name, name, strnlen(name, 32));
|
|
if (SQL_ERROR == Sql_Query(mmysql_handle, "UPDATE `%s` SET `value`='%d' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg_table, m->u.i, esc_name, i))
|
|
Sql_ShowDebug(mmysql_handle);
|
|
} else {
|
|
char esc_str[2 * 255 + 1];
|
|
char esc_name[32 * 2 + 1];
|
|
Sql_EscapeStringLen(mmysql_handle, esc_name, name, strnlen(name, 32));
|
|
Sql_EscapeStringLen(mmysql_handle, esc_str, m->u.str, safestrnlen(m->u.str, 255));
|
|
if (SQL_ERROR == Sql_Query(mmysql_handle, "UPDATE `%s` SET `value`='%s' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg_table, esc_str, esc_name, i))
|
|
Sql_ShowDebug(mmysql_handle);
|
|
}
|
|
m->save = false;
|
|
}
|
|
}
|
|
dbi_destroy(iter);
|
|
mapreg_dirty = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Timer event to auto-save permanent variables.
|
|
*/
|
|
static TIMER_FUNC(script_autosave_mapreg){
|
|
script_save_mapreg();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Destroys a mapreg_save structure, freeing the contained string, if any.
|
|
*
|
|
* @see DBApply
|
|
*/
|
|
int mapreg_destroyreg(DBKey key, DBData *data, va_list ap)
|
|
{
|
|
struct mapreg_save *m = NULL;
|
|
|
|
if (data->type != DB_DATA_PTR) // Sanity check
|
|
return 0;
|
|
|
|
m = static_cast<mapreg_save *>(db_data2ptr(data));
|
|
|
|
if (m->is_string) {
|
|
if (m->u.str)
|
|
aFree(m->u.str);
|
|
}
|
|
ers_free(mapreg_ers, m);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Reloads mapregs, saving to database beforehand.
|
|
*
|
|
* This has the effect of clearing the temporary variables, and
|
|
* reloading the permanent ones.
|
|
*/
|
|
void mapreg_reload(void)
|
|
{
|
|
script_save_mapreg();
|
|
|
|
regs.vars->clear(regs.vars, mapreg_destroyreg);
|
|
|
|
if (regs.arrays) {
|
|
regs.arrays->destroy(regs.arrays, script_free_array_db);
|
|
regs.arrays = NULL;
|
|
}
|
|
|
|
script_load_mapreg();
|
|
}
|
|
|
|
/**
|
|
* Finalizer.
|
|
*/
|
|
void mapreg_final(void)
|
|
{
|
|
script_save_mapreg();
|
|
|
|
regs.vars->destroy(regs.vars, mapreg_destroyreg);
|
|
|
|
ers_destroy(mapreg_ers);
|
|
|
|
if (regs.arrays)
|
|
regs.arrays->destroy(regs.arrays, script_free_array_db);
|
|
}
|
|
|
|
/**
|
|
* Initializer.
|
|
*/
|
|
void mapreg_init(void)
|
|
{
|
|
regs.vars = i64db_alloc(DB_OPT_BASE);
|
|
mapreg_ers = ers_new(sizeof(struct mapreg_save), "mapreg.c:mapreg_ers", ERS_OPT_CLEAN);
|
|
|
|
skip_insert = false;
|
|
regs.arrays = NULL;
|
|
|
|
script_load_mapreg();
|
|
|
|
add_timer_func_list(script_autosave_mapreg, "script_autosave_mapreg");
|
|
add_timer_interval(gettick() + MAPREG_AUTOSAVE_INTERVAL, script_autosave_mapreg, 0, 0, MAPREG_AUTOSAVE_INTERVAL);
|
|
}
|
|
|
|
/**
|
|
* Loads the mapreg configuration file.
|
|
*/
|
|
bool mapreg_config_read(const char* w1, const char* w2)
|
|
{
|
|
if(!strcmpi(w1, "mapreg_table"))
|
|
safestrncpy(mapreg_table, w2, sizeof(mapreg_table));
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|