summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/emap/hashtable.c209
-rw-r--r--src/emap/hashtable.h43
-rw-r--r--src/emap/init.c14
-rw-r--r--src/emap/script_buildins.c181
-rw-r--r--src/emap/script_buildins.h10
6 files changed, 459 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index a440726..b9812f2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,6 +42,8 @@ MAP_SRC = emap/atcommand.c \
emap/craft.h \
emap/craftconf.c \
emap/craftconf.h \
+ emap/hashtable.c \
+ emap/hashtable.h \
emap/horse.c \
emap/horse.h \
emap/init.c \
diff --git a/src/emap/hashtable.c b/src/emap/hashtable.c
new file mode 100644
index 0000000..9d2908d
--- /dev/null
+++ b/src/emap/hashtable.c
@@ -0,0 +1,209 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2015 - 2016 Evol developers
+
+#include "common/hercules.h"
+
+#include "common/db.h"
+#include "common/memmgr.h"
+#include "emap/hashtable.h"
+
+struct htreg_interface htreg_s;
+struct htreg_interface *htreg;
+
+int64 htreg_new_hashtable(void)
+{
+ int64 id = htreg->last_id++;
+ struct DBMap *ht = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA,
+ HT_MAX_KEY_LEN);
+ i64db_put(htreg->htables, id, ht);
+ return id;
+}
+
+bool htreg_destroy_hashtable(int64 id)
+{
+ struct DBMap *ht = i64db_get(htreg->htables, id);
+ if (ht)
+ {
+ db_destroy(ht);
+ i64db_remove(htreg->htables, id);
+ return true;
+ }
+ return false;
+}
+
+bool htreg_hashtable_exists(int64 id)
+{
+ return i64db_exists(htreg->htables, id);
+}
+
+int64 htreg_hashtable_size(int64 id)
+{
+ struct DBMap *ht = i64db_get(htreg->htables, id);
+ if (ht)
+ return db_size(ht);
+ return 0;
+}
+
+bool htreg_clear_hashtable(int64 id)
+{
+ struct DBMap *ht = i64db_get(htreg->htables, id);
+ if (ht)
+ {
+ db_clear(ht);
+ return true;
+ }
+ return false;
+}
+
+const struct DBData* htreg_hashtable_getvalue(int64 id, const char *key,
+ const struct DBData *defval)
+{
+ struct DBMap *ht = i64db_get(htreg->htables, id);
+ if (ht)
+ {
+ struct DBData *val = ht->get(ht, DB->str2key(key));
+ return val ? val : defval;
+ }
+ return NULL;
+}
+
+bool htreg_hashtable_setvalue(int64 id, const char *key,
+ struct DBData value)
+{
+ struct DBMap *ht = i64db_get(htreg->htables, id);
+ if (!ht)
+ return false;
+
+ bool keep = true;
+
+ switch(value.type)
+ {
+ case DB_DATA_INT:
+ case DB_DATA_UINT:
+ keep = value.u.i;
+ break;
+ case DB_DATA_PTR:
+ keep = value.u.ptr && *(char*)value.u.ptr;
+ break;
+ }
+
+ if (keep)
+ ht->put(ht, DB->str2key(key), value, NULL);
+ else
+ strdb_remove(ht, key);
+
+ return true;
+}
+
+/**
+ * Iterators
+ */
+int64 htreg_create_iterator(int64 htId)
+{
+ struct DBMap *ht = i64db_get(htreg->htables, htId);
+ if (ht)
+ {
+ int64 id = htreg->last_iterator_id++;
+ struct DBIterator *it = db_iterator(ht);
+ i64db_put(htreg->iterators, id, it);
+ return id;
+ }
+ return 0;
+}
+
+bool htreg_destroy_iterator(int64 id)
+{
+ struct DBIterator *it = i64db_get(htreg->iterators, id);
+ if (it)
+ {
+ dbi_destroy(it);
+ return true;
+ }
+ return false;
+}
+
+bool htreg_iterator_check(int64 id)
+{
+ struct DBIterator *it = i64db_get(htreg->iterators, id);
+ return it ? dbi_exists(it) : false;
+}
+
+bool htreg_iterator_exists(int64 id)
+{
+ return i64db_exists(htreg->iterators, id);
+}
+
+const char* htreg_iterator_nextkey(int64 id)
+{
+ struct DBIterator *it = i64db_get(htreg->iterators, id);
+ if (it)
+ {
+ union DBKey key;
+ it->next(it, &key);
+ if (dbi_exists(it))
+ return key.str;
+ }
+ return NULL;
+}
+
+/**
+ * Initializer.
+ */
+void htreg_init(void)
+{
+ htreg->htables = i64db_alloc(DB_OPT_BASE);
+ htreg->iterators = i64db_alloc(DB_OPT_BASE);
+}
+
+/**
+ * Finalizer.
+ */
+void htreg_final(void)
+{
+ struct DBIterator *iter = db_iterator(htreg->htables);
+ struct DBMap *ht;
+
+ for(ht=dbi_first(iter); dbi_exists(iter); ht=dbi_next(iter))
+ db_destroy(ht);
+
+ dbi_destroy(iter);
+ db_destroy(htreg->htables);
+
+ // NOTE: maybe I should destroy iteratos before hashtables
+ struct DBIterator *it;
+ iter = db_iterator(htreg->iterators);
+
+ for (it=dbi_first(iter); dbi_exists(iter); it=dbi_next(iter))
+ dbi_destroy(it);
+
+ dbi_destroy(iter);
+ db_destroy(htreg->iterators);
+}
+
+/**
+ * Interface defaults initializer.
+ */
+void htreg_defaults(void)
+{
+ htreg = &htreg_s;
+
+ htreg->last_id = 1;
+ htreg->htables = NULL;
+ htreg->init = htreg_init;
+ htreg->final = htreg_final;
+ htreg->new_hashtable = htreg_new_hashtable;
+ htreg->destroy_hashtable = htreg_destroy_hashtable;
+ htreg->hashtable_exists = htreg_hashtable_exists;
+ htreg->hashtable_size = htreg_hashtable_size;
+ htreg->clear_hashtable = htreg_clear_hashtable;
+ htreg->hashtable_getvalue = htreg_hashtable_getvalue;
+ htreg->hashtable_setvalue = htreg_hashtable_setvalue;
+
+ htreg->last_iterator_id = 1;
+ htreg->iterators = NULL;
+ htreg->create_iterator = htreg_create_iterator;
+ htreg->destroy_iterator = htreg_destroy_iterator;
+ htreg->iterator_check = htreg_iterator_check;
+ htreg->iterator_exists = htreg_iterator_exists;
+ htreg->iterator_nextkey = htreg_iterator_nextkey;
+}
diff --git a/src/emap/hashtable.h b/src/emap/hashtable.h
new file mode 100644
index 0000000..44712cd
--- /dev/null
+++ b/src/emap/hashtable.h
@@ -0,0 +1,43 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2015 - 2016 Evol developers
+
+#ifndef EVOL_HASH_TABLE
+#define EVOL_HASH_TABLE
+
+#include "common/hercules.h"
+#include "common/db.h"
+
+#define HT_MAX_KEY_LEN 32
+
+struct htreg_interface
+{
+ int64 last_id;
+ int64 last_iterator_id;
+ struct DBMap *htables;
+ struct DBMap *iterators;
+ void (*init) (void);
+ void (*final) (void);
+ int64 (*new_hashtable) (void);
+ bool (*destroy_hashtable) (int64 id);
+ bool (*hashtable_exists) (int64 id);
+ int64 (*hashtable_size) (int64 id);
+ bool (*clear_hashtable) (int64 id);
+ const struct DBData* (*hashtable_getvalue) (int64 id, const char *key,
+ const struct DBData *defval);
+ bool (*hashtable_setvalue) (int64 id, const char *key,
+ const struct DBData value);
+
+ int64 (*create_iterator) (int64 id);
+ bool (*destroy_iterator) (int64 id);
+ bool (*iterator_check) (int64 id);
+ bool (*iterator_exists) (int64 id);
+ const char* (*iterator_nextkey) (int64 id);
+};
+
+void htreg_defaults(void);
+void htreg_init(void);
+void htreg_final(void);
+
+HPShared struct htreg_interface *htreg;
+
+#endif // EVOL_HASH_TABLE
diff --git a/src/emap/init.c b/src/emap/init.c
index d75f2c2..3a586dd 100644
--- a/src/emap/init.c
+++ b/src/emap/init.c
@@ -49,6 +49,7 @@
#include "emap/config.h"
#include "emap/craft.h"
#include "emap/craftconf.h"
+#include "emap/hashtable.h"
#include "emap/itemdb.h"
#include "emap/lang.h"
#include "emap/mail.h"
@@ -84,6 +85,7 @@ HPExport void plugin_init (void)
{
isInit = false;
status_init();
+ htreg_init();
addAtcommand("setskill", setSkill);
addAtcommand("slide", slide);
@@ -155,6 +157,16 @@ HPExport void plugin_init (void)
addScriptCommand("setskin", "s", setSkin);
addScriptCommand("emotion", "i??", emotion);
addScriptCommand("setlook", "ii", setLook);
+ addScriptCommand("htnew", "", htNew);
+ addScriptCommand("htget", "is?", htGet);
+ addScriptCommand("htput", "isv", htPut);
+ addScriptCommand("htclear", "i", htClear);
+ addScriptCommand("htdelete", "i", htDelete);
+ addScriptCommand("htsize", "i", htSize);
+ addScriptCommand("htiterator", "i", htIterator);
+ addScriptCommand("htinextkey", "i", htiNextKey);
+ addScriptCommand("hticheck", "i", htiCheck);
+ addScriptCommand("htidelete", "i", htiDelete);
do_init_langs();
@@ -276,6 +288,7 @@ HPExport void plugin_init (void)
HPExport void server_preinit (void)
{
interfaces_init_common();
+ htreg_defaults();
setDefaultMap();
addMapInterConf("default_map", config_default_map);
@@ -301,5 +314,6 @@ HPExport void plugin_final (void)
do_final_craft();
do_final_craftconf();
commonClean();
+ htreg_final();
isInit = false;
}
diff --git a/src/emap/script_buildins.c b/src/emap/script_buildins.c
index e37026d..a7b51fb 100644
--- a/src/emap/script_buildins.c
+++ b/src/emap/script_buildins.c
@@ -22,6 +22,7 @@
#include "emap/craft.h"
#include "emap/lang.h"
#include "emap/map.h"
+#include "emap/hashtable.h"
#include "emap/scriptdefines.h"
#include "emap/send.h"
#include "emap/data/bgd.h"
@@ -1803,3 +1804,183 @@ BUILDIN(setLook)
send_changelook2(sd, &sd->bl, sd->bl.id, type, val, 0, NULL, 0, AREA);
return true;
}
+
+#define checkHashTableExists(id) \
+ if (!htreg->hashtable_exists(id)) \
+ { \
+ ShowError("%s: hashtable with id=%ld does not exist\n", __func__, id); \
+ script_pushint(st, 0); \
+ return false; \
+ }
+
+BUILDIN(htNew)
+{
+ int64 id = htreg->new_hashtable();
+ script_pushint(st, id);
+ return true;
+}
+
+BUILDIN(htGet)
+{
+ int64 id = script_getnum(st, 2);
+ checkHashTableExists(id);
+
+ struct DBData defval_s;
+ struct DBData *defval = &defval_s;
+ const char * key = script_getstr(st, 3);
+
+ if (script_hasdata(st, 4))
+ {
+ if (script_isstringtype(st, 4))
+ {
+ defval->type = DB_DATA_PTR;
+ defval->u.ptr = (void*)script_getstr(st, 4);
+ }
+ else if (script_isinttype(st, 4))
+ {
+ defval->type = DB_DATA_INT;
+ defval->u.i = script_getnum(st, 4);
+ }
+ else
+ {
+ ShowError("usage: htget(<id>, <strkey>[ ,<defval>])\n");
+ return false;
+ }
+ }
+ else
+ {
+ defval = NULL;
+ }
+
+ const struct DBData *result = htreg->hashtable_getvalue(id, key, defval);
+ if (result)
+ {
+ switch(result->type)
+ {
+ case DB_DATA_INT:
+ case DB_DATA_UINT:
+ script_pushint(st, result->u.i);
+ break;
+ case DB_DATA_PTR:
+ script_pushstrcopy(st, result->u.ptr);
+ break;
+ }
+ }
+ else
+ {
+ script_pushint(st, 0);
+ }
+
+ return true;
+}
+
+BUILDIN(htPut)
+{
+ int64 id = script_getnum(st, 2);
+ checkHashTableExists(id);
+
+ struct DBData value;
+ const char * key = script_getstr(st, 3);
+
+ if (script_isstringtype(st, 4))
+ {
+ value.type = DB_DATA_PTR;
+ value.u.ptr = (void*)aStrdup(script_getstr(st, 4));
+ }
+ else if (script_isinttype(st, 4))
+ {
+ value.type = DB_DATA_INT;
+ value.u.i = script_getnum(st, 4);
+ }
+ else
+ {
+ ShowError("usage: htput(<id>, <strkey>, <newval>)\n");
+ return false;
+ }
+
+ htreg->hashtable_setvalue(id, key, value);
+ return true;
+}
+
+BUILDIN(htClear)
+{
+ int64 id = script_getnum(st, 2);
+ checkHashTableExists(id);
+
+ htreg->clear_hashtable(id);
+ return true;
+}
+
+BUILDIN(htDelete)
+{
+ int64 id = script_getnum(st, 2);
+ checkHashTableExists(id);
+
+ htreg->destroy_hashtable(id);
+ return true;
+}
+
+BUILDIN(htSize)
+{
+ int64 id = script_getnum(st, 2);
+ checkHashTableExists(id);
+
+ script_pushint(st, htreg->hashtable_size(id));
+ return true;
+}
+
+BUILDIN(htIterator)
+{
+ int64 id = script_getnum(st, 2);
+ checkHashTableExists(id);
+
+ script_pushint(st, htreg->create_iterator(id));
+ return true;
+}
+
+#undef checkHashTableExists
+
+#define checkHtIteratorExists(id) \
+ if (!htreg->iterator_exists(id)) \
+ { \
+ ShowError("%s: htIterator with id=%ld does not exist\n", __func__, id); \
+ script_pushint(st, 0); \
+ return false; \
+ }
+
+BUILDIN(htiNextKey)
+{
+ int64 id = script_getnum(st, 2);
+ checkHtIteratorExists(id);
+
+ const char * key = htreg->iterator_nextkey(id);
+ if (key)
+ script_pushstrcopy(st, key);
+ else
+ script_pushstrcopy(st, "");
+ return true;
+}
+
+BUILDIN(htiCheck)
+{
+ int64 id = script_getnum(st, 2);
+ checkHtIteratorExists(id);
+
+ if (htreg->iterator_check(id))
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
+
+ return true;
+}
+
+BUILDIN(htiDelete)
+{
+ int64 id = script_getnum(st, 2);
+ checkHtIteratorExists(id);
+
+ htreg->destroy_iterator(id);
+ return true;
+}
+
+#undef checkHtIteratorExists
diff --git a/src/emap/script_buildins.h b/src/emap/script_buildins.h
index 1d83813..6eb109b 100644
--- a/src/emap/script_buildins.h
+++ b/src/emap/script_buildins.h
@@ -71,5 +71,15 @@ BUILDIN(findCraftEntry);
BUILDIN(useCraft);
BUILDIN(getCraftCode);
BUILDIN(setLook);
+BUILDIN(htNew);
+BUILDIN(htGet);
+BUILDIN(htPut);
+BUILDIN(htClear);
+BUILDIN(htDelete);
+BUILDIN(htSize);
+BUILDIN(htIterator);
+BUILDIN(htiNextKey);
+BUILDIN(htiCheck);
+BUILDIN(htiDelete);
#endif // EVOL_MAP_SCRIPT_BUILDINS