summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshennetsind <ind@henn.et>2014-01-11 14:02:59 -0200
committershennetsind <ind@henn.et>2014-01-11 14:02:59 -0200
commit82b583b5ef4e729ad2c3c74b26adce16a145605a (patch)
tree5bb20b90edd899b06abe9853dba06383a9379c06
parent56649bda4b2f62cf42847830546b5856234b3178 (diff)
downloadhercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.tar.gz
hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.tar.bz2
hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.tar.xz
hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.zip
Hercules 1st 2014 MegaPatch
http://hercules.ws/board/topic/3886-hercules-1st-2014-megapatch/ Signed-off-by: shennetsind <ind@henn.et>
-rw-r--r--conf/inter-server.conf7
-rw-r--r--sql-files/main.sql99
-rw-r--r--sql-files/upgrades/2014-01-04--16-47.sql61
-rw-r--r--sql-files/upgrades/index.txt1
-rw-r--r--src/char/char.c112
-rw-r--r--src/char/char.h15
-rw-r--r--src/char/inter.c417
-rw-r--r--src/common/db.c175
-rw-r--r--src/common/db.h124
-rw-r--r--src/common/mmo.h41
-rw-r--r--src/common/socket.c4
-rw-r--r--src/login/account.h10
-rw-r--r--src/login/account_sql.c271
-rw-r--r--src/login/login.c51
-rw-r--r--src/login/login.h5
-rw-r--r--src/map/atcommand.c12
-rw-r--r--src/map/battleground.c6
-rw-r--r--src/map/chrif.c10
-rw-r--r--src/map/clif.c2
-rw-r--r--src/map/duel.c4
-rw-r--r--src/map/instance.c5
-rw-r--r--src/map/instance.h5
-rw-r--r--src/map/intif.c259
-rw-r--r--src/map/intif.h2
-rw-r--r--src/map/mapreg.h18
-rw-r--r--src/map/mapreg_sql.c99
-rw-r--r--src/map/mob.c4
-rw-r--r--src/map/pc.c589
-rw-r--r--src/map/pc.h63
-rw-r--r--src/map/script.c835
-rw-r--r--src/map/script.h73
-rw-r--r--src/map/skill.c16
-rw-r--r--src/map/trade.c2
-rw-r--r--src/map/unit.c21
34 files changed, 2144 insertions, 1274 deletions
diff --git a/conf/inter-server.conf b/conf/inter-server.conf
index d4a75ee51..96d43973b 100644
--- a/conf/inter-server.conf
+++ b/conf/inter-server.conf
@@ -76,6 +76,8 @@ mysql_reconnect_count:1
//Shared
interreg_db: interreg
+global_acc_reg_num_db: global_acc_reg_num_db
+global_acc_reg_str_db: global_acc_reg_str_db
// Char Database Tables
char_db: char
@@ -85,7 +87,6 @@ cart_db: cart_inventory
inventory_db: inventory
charlog_db: charlog
storage_db: storage
-reg_db: global_reg_value
skill_db: skill
interlog_db: interlog
memo_db: memo
@@ -110,6 +111,10 @@ mercenary_owner_db: mercenary_owner
ragsrvinfo_db: ragsrvinfo
elemental_db: elemental
account_data_db: account_data
+acc_reg_num_db: acc_reg_num_db
+acc_reg_str_db: acc_reg_str_db
+char_reg_str_db: char_reg_str_db
+char_reg_num_db: char_reg_num_db
// Map Database Tables
item_db_db: item_db
diff --git a/sql-files/main.sql b/sql-files/main.sql
index 30882546e..398bdcfe4 100644
--- a/sql-files/main.sql
+++ b/sql-files/main.sql
@@ -189,20 +189,6 @@ CREATE TABLE IF NOT EXISTS `hotkey` (
) ENGINE=MyISAM;
--
--- Table structure for table `global_reg_value`
---
-
-CREATE TABLE IF NOT EXISTS `global_reg_value` (
- `char_id` int(11) unsigned NOT NULL default '0',
- `str` varchar(255) NOT NULL default '',
- `value` varchar(255) NOT NULL default '0',
- `type` tinyint(1) NOT NULL default '3',
- `account_id` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`char_id`,`str`,`account_id`),
- KEY `account_id` (`account_id`)
-) ENGINE=MyISAM;
-
---
-- Table structure for table `guild`
--
@@ -462,11 +448,10 @@ INSERT INTO `login` (`account_id`, `userid`, `user_pass`, `sex`, `email`) VALUES
--
CREATE TABLE IF NOT EXISTS `mapreg` (
- `varname` varchar(32) NOT NULL,
+ `varname` varchar(32) BINARY NOT NULL,
`index` int(11) unsigned NOT NULL default '0',
`value` varchar(255) NOT NULL,
- KEY `varname` (`varname`),
- KEY `index` (`index`)
+ PRIMARY KEY (`varname`,`index`)
) ENGINE=MyISAM;
--
@@ -672,6 +657,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1383955424);
INSERT INTO `sql_updates` (`timestamp`) VALUES (1384545461);
INSERT INTO `sql_updates` (`timestamp`) VALUES (1384588175);
INSERT INTO `sql_updates` (`timestamp`) VALUES (1387844126);
+INSERT INTO `sql_updates` (`timestamp`) VALUES (1388854043);
INSERT INTO `sql_updates` (`timestamp`) VALUES (1389028967);
--
@@ -745,6 +731,85 @@ CREATE TABLE IF NOT EXISTS `npc_market_data` (
) ENGINE=MyISAM;
--
+-- Table structure for table `acc_reg_num_db`
+--
+
+CREATE TABLE IF NOT EXISTS `acc_reg_num_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` int(11) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+
+--
+-- Table structure for table `acc_reg_str_db`
+--
+
+CREATE TABLE IF NOT EXISTS `acc_reg_str_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` varchar(254) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+
+--
+-- Table structure for table `char_reg_num_db`
+--
+
+CREATE TABLE IF NOT EXISTS `char_reg_num_db` (
+ `char_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` int(11) NOT NULL default '0',
+ PRIMARY KEY (`char_id`,`key`,`index`),
+ KEY `char_id` (`char_id`)
+) ENGINE=MyISAM;
+
+--
+-- Table structure for table `char_reg_str_db`
+--
+
+CREATE TABLE IF NOT EXISTS `char_reg_str_db` (
+ `char_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` varchar(254) NOT NULL default '0',
+ PRIMARY KEY (`char_id`,`key`,`index`),
+ KEY `char_id` (`char_id`)
+) ENGINE=MyISAM;
+
+--
+-- Table structure for table `global_acc_reg_num_db`
+--
+
+CREATE TABLE IF NOT EXISTS `global_acc_reg_num_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` int(11) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+
+--
+-- Table structure for table `global_acc_reg_str_db`
+--
+
+
+CREATE TABLE IF NOT EXISTS `global_acc_reg_str_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` varchar(254) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+
+--
-- Table structure for table `autotrade_merchants`
--
diff --git a/sql-files/upgrades/2014-01-04--16-47.sql b/sql-files/upgrades/2014-01-04--16-47.sql
new file mode 100644
index 000000000..a60ec1d24
--- /dev/null
+++ b/sql-files/upgrades/2014-01-04--16-47.sql
@@ -0,0 +1,61 @@
+#1388854043
+ALTER TABLE `mapreg` ADD PRIMARY KEY (`varname`, `index`);
+ALTER TABLE `mapreg` DROP INDEX `varname`;
+ALTER TABLE `mapreg` DROP INDEX `index`;
+ALTER TABLE `mapreg` MODIFY `varname` varchar(32) BINARY NOT NULL;
+CREATE TABLE IF NOT EXISTS `acc_reg_num_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` int(11) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+CREATE TABLE IF NOT EXISTS `acc_reg_str_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` varchar(254) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+CREATE TABLE IF NOT EXISTS `char_reg_num_db` (
+ `char_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` int(11) NOT NULL default '0',
+ PRIMARY KEY (`char_id`,`key`,`index`),
+ KEY `char_id` (`char_id`)
+) ENGINE=MyISAM;
+CREATE TABLE IF NOT EXISTS `char_reg_str_db` (
+ `char_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` varchar(254) NOT NULL default '0',
+ PRIMARY KEY (`char_id`,`key`,`index`),
+ KEY `char_id` (`char_id`)
+) ENGINE=MyISAM;
+CREATE TABLE IF NOT EXISTS `global_acc_reg_num_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` int(11) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+CREATE TABLE IF NOT EXISTS `global_acc_reg_str_db` (
+ `account_id` int(11) unsigned NOT NULL default '0',
+ `key` varchar(32) BINARY NOT NULL default '',
+ `index` int(11) unsigned NOT NULL default '0',
+ `value` varchar(254) NOT NULL default '0',
+ PRIMARY KEY (`account_id`,`key`,`index`),
+ KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;
+INSERT INTO `acc_reg_num_db` (`account_id`, `key`, `index`, `value`) SELECT `account_id`, `str`, 0, `value` FROM `global_reg_value` WHERE `type` = 2 AND `str` NOT LIKE '%$';
+INSERT INTO `acc_reg_str_db` (`account_id`, `key`, `index`, `value`) SELECT `account_id`, `str`, 0, `value` FROM `global_reg_value` WHERE `type` = 2 AND `str` LIKE '%$';
+INSERT INTO `char_reg_num_db` (`char_id`, `key`, `index`, `value`) SELECT `char_id`, `str`, 0, `value` FROM `global_reg_value` WHERE `type` = 3 AND `str` NOT LIKE '%$';
+INSERT INTO `char_reg_str_db` (`char_id`, `key`, `index`, `value`) SELECT `char_id`, `str`, 0, `value` FROM `global_reg_value` WHERE `type` = 3 AND `str` LIKE '%$';
+INSERT INTO `global_acc_reg_num_db` (`account_id`, `key`, `index`, `value`) SELECT `account_id`, `str`, 0, `value` FROM `global_reg_value` WHERE `type` = 1 AND `str` NOT LIKE '%$';
+INSERT INTO `global_acc_reg_str_db` (`account_id`, `key`, `index`, `value`) SELECT `account_id`, `str`, 0, `value` FROM `global_reg_value` WHERE `type` = 1 AND `str` LIKE '%$';
+#DROP TABLE `global_reg_value`;
+INSERT INTO `sql_updates` (`timestamp`) VALUES (1388854043); \ No newline at end of file
diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt
index ce75fa882..bf404d919 100644
--- a/sql-files/upgrades/index.txt
+++ b/sql-files/upgrades/index.txt
@@ -16,4 +16,5 @@
2013-11-16--07-49.sql
2013-11-18--08-23.sql
2013-12-24--00-15.sql
+2014-01-04--16-47.sql
2014-01-06--17-22.sql \ No newline at end of file
diff --git a/src/char/char.c b/src/char/char.c
index 9b3f1443d..a6588dc09 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -45,7 +45,6 @@ char inventory_db[256] = "inventory";
char charlog_db[256] = "charlog";
char storage_db[256] = "storage";
char interlog_db[256] = "interlog";
-char reg_db[256] = "global_reg_value";
char skill_db[256] = "skill";
char memo_db[256] = "memo";
char guild_db[256] = "guild";
@@ -71,6 +70,10 @@ char ragsrvinfo_db[256] = "ragsrvinfo";
char elemental_db[256] = "elemental";
char interreg_db[32] = "interreg";
char account_data_db[256] = "account_data";
+char acc_reg_num_db[32] = "acc_reg_num_db";
+char acc_reg_str_db[32] = "acc_reg_str_db";
+char char_reg_str_db[32] = "char_reg_str_db";
+char char_reg_num_db[32] = "char_reg_num_db";
// show loading/saving messages
int save_log = 1;
@@ -1793,7 +1796,9 @@ int delete_char_sql(int char_id)
Sql_ShowDebug(sql_handle);
/* delete character registry */
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) )
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_reg_str_db, char_id) )
+ Sql_ShowDebug(sql_handle);
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_reg_num_db, char_id) )
Sql_ShowDebug(sql_handle);
/* delete skills */
@@ -2460,17 +2465,12 @@ int parse_fromlogin(int fd) {
break;
// reply to an account_reg2 registry request
- case 0x2729:
+ case 0x3804:
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
-
- { //Receive account_reg2 registry, forward to map servers.
- unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
- memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
- WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
- mapif_sendall(buf, WBUFW(buf,2));
+ //Receive account_reg2 registry, forward to map servers.
+ mapif_sendall(RFIFOP(fd, 0), RFIFOW(fd,2));
RFIFOSKIP(fd, RFIFOW(fd,2));
- }
break;
// State change of account/ban notification (from login-server)
@@ -2603,21 +2603,76 @@ int request_accreg2(int account_id, int char_id)
}
return 0;
}
-
-//Send packet forward to login-server for account saving
-int save_accreg2(unsigned char* buf, int len)
-{
- if (login_fd > 0) {
- WFIFOHEAD(login_fd,len+4);
- memcpy(WFIFOP(login_fd,4), buf, len);
- WFIFOW(login_fd,0) = 0x2728;
- WFIFOW(login_fd,2) = len+4;
- WFIFOSET(login_fd,len+4);
- return 1;
+/**
+ * Handles global account reg saving that continues with global_accreg_to_login_add and global_accreg_to_send
+ **/
+void global_accreg_to_login_start (int account_id, int char_id) {
+ WFIFOHEAD(login_fd, 60000 + 300);
+ WFIFOW(login_fd,0) = 0x2728;
+ WFIFOW(login_fd,2) = 14;
+ WFIFOL(login_fd,4) = account_id;
+ WFIFOL(login_fd,8) = char_id;
+ WFIFOW(login_fd,12) = 0;/* count */
+}
+/**
+ * Completes global account reg saving that starts global_accreg_to_login_start and continues with global_accreg_to_login_add
+ **/
+void global_accreg_to_login_send (void) {
+ WFIFOSET(login_fd, WFIFOW(login_fd,2));
+}
+/**
+ * Handles global account reg saving that starts global_accreg_to_login_start and ends with global_accreg_to_send
+ **/
+void global_accreg_to_login_add (const char *key, unsigned int index, intptr_t val, bool is_string) {
+ int nlen = WFIFOW(login_fd, 2);
+ size_t len;
+
+ len = strlen(key)+1;
+
+ WFIFOB(login_fd, nlen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ nlen += 1;
+
+ safestrncpy((char*)WFIFOP(login_fd,nlen), key, len);
+ nlen += len;
+
+ WFIFOL(login_fd, nlen) = index;
+ nlen += 4;
+
+ if( is_string ) {
+ WFIFOB(login_fd, nlen) = val ? 2 : 3;
+ nlen += 1;
+
+ if( val ) {
+ char *sval = (char*)val;
+ len = strlen(sval)+1;
+
+ WFIFOB(login_fd, nlen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ nlen += 1;
+
+ safestrncpy((char*)WFIFOP(login_fd,nlen), sval, len);
+ nlen += len;
+ }
+
+ } else {
+ WFIFOB(login_fd, nlen) = val ? 0 : 1;
+ nlen += 1;
+
+ if( val ) {
+ WFIFOL(login_fd, nlen) = (int)val;
+ nlen += 4;
+ }
+
+ }
+
+ WFIFOW(login_fd,12) += 1;
+
+ WFIFOW(login_fd, 2) = nlen;
+ if( WFIFOW(login_fd, 2) > 60000 ) {
+ int account_id = WFIFOL(login_fd,4), char_id = WFIFOL(login_fd,8);
+ global_accreg_to_login_send();
+ global_accreg_to_login_start(account_id,char_id);/* prepare next */
}
- return 0;
}
-
void char_read_fame_list(void) {
int i;
char* data;
@@ -4901,8 +4956,6 @@ void sql_config_read(const char* cfgName)
safestrncpy(charlog_db, w2, sizeof(charlog_db));
else if(!strcmpi(w1,"storage_db"))
safestrncpy(storage_db, w2, sizeof(storage_db));
- else if(!strcmpi(w1,"reg_db"))
- safestrncpy(reg_db, w2, sizeof(reg_db));
else if(!strcmpi(w1,"skill_db"))
safestrncpy(skill_db, w2, sizeof(skill_db));
else if(!strcmpi(w1,"interlog_db"))
@@ -4955,6 +5008,15 @@ void sql_config_read(const char* cfgName)
safestrncpy(interreg_db,w2,sizeof(interreg_db));
else if(!strcmpi(w1,"account_data_db"))
safestrncpy(account_data_db,w2,sizeof(account_data_db));
+ else if(!strcmpi(w1,"char_reg_num_db"))
+ safestrncpy(char_reg_num_db, w2, sizeof(char_reg_num_db));
+ else if(!strcmpi(w1,"char_reg_str_db"))
+ safestrncpy(char_reg_str_db, w2, sizeof(char_reg_str_db));
+ else if(!strcmpi(w1,"acc_reg_str_db"))
+ safestrncpy(acc_reg_str_db, w2, sizeof(acc_reg_str_db));
+ else if(!strcmpi(w1,"acc_reg_num_db"))
+ safestrncpy(acc_reg_num_db, w2, sizeof(acc_reg_num_db));
+
//support the import command, just like any other config
else if(!strcmpi(w1,"import"))
sql_config_read(w2);
diff --git a/src/char/char.h b/src/char/char.h
index c6aa1b66d..3e3774c1f 100644
--- a/src/char/char.h
+++ b/src/char/char.h
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#ifndef _CHAR_SQL_H_
#define _CHAR_SQL_H_
@@ -68,7 +69,6 @@ int char_child(int parent_id, int child_id);
int char_family(int pl1,int pl2,int pl3);
int request_accreg2(int account_id, int char_id);
-int save_accreg2(unsigned char* buf, int len);
int login_fd;
extern int char_name_option;
extern char char_name_letters[];
@@ -83,7 +83,6 @@ extern char inventory_db[256];
extern char charlog_db[256];
extern char storage_db[256];
extern char interlog_db[256];
-extern char reg_db[256];
extern char skill_db[256];
extern char memo_db[256];
extern char guild_db[256];
@@ -106,6 +105,10 @@ extern char mercenary_owner_db[256];
extern char ragsrvinfo_db[256];
extern char elemental_db[256];
extern char interreg_db[32];
+extern char acc_reg_num_db[32];
+extern char acc_reg_str_db[32];
+extern char char_reg_str_db[32];
+extern char char_reg_num_db[32];
extern int db_use_sql_item_db;
extern int db_use_sql_mob_db;
@@ -114,4 +117,8 @@ extern int db_use_sql_mob_skill_db;
extern int guild_exp_rate;
extern int log_inter;
+void global_accreg_to_login_start (int account_id, int char_id);
+void global_accreg_to_login_send (void);
+void global_accreg_to_login_add (const char *key, unsigned int index, intptr_t val, bool is_string);
+
#endif /* _CHAR_SQL_H_ */
diff --git a/src/char/inter.c b/src/char/inter.c
index 63e1564ff..34ecebd36 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -42,7 +42,6 @@ char char_server_pw[32] = "ragnarok";
char char_server_db[32] = "ragnarok";
char default_codepage[32] = ""; //Feature by irmin.
-static struct accreg *accreg_pt;
unsigned int party_share_level = 10;
// recv. packet list
@@ -592,127 +591,225 @@ void mapif_parse_accinfo(int fd) {
return;
}
-//--------------------------------------------------------
-// Save registry to sql
-int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type)
-{
- struct global_reg* r;
- StringBuf buf;
- int i;
-
- if( account_id <= 0 )
- return 0;
- reg->account_id = account_id;
- reg->char_id = char_id;
-
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- switch( type )
- {
- case 3: //Char Reg
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) )
- Sql_ShowDebug(sql_handle);
- account_id = 0;
- break;
- case 2: //Account Reg
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) )
- Sql_ShowDebug(sql_handle);
- char_id = 0;
- break;
- case 1: //Account2 Reg
- ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
- return 0;
- default:
- ShowError("inter_accreg_tosql: Invalid type %d\n", type);
- return 0;
- }
-
- if( reg->reg_num <= 0 )
- return 0;
-
- StrBuf->Init(&buf);
- StrBuf->Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db);
-
- for( i = 0; i < reg->reg_num; ++i ) {
- r = &reg->reg[i];
- if( r->str[0] != '\0' && r->value[0] != '\0' ) {
- char str[32];
- char val[256];
-
- if( i > 0 )
- StrBuf->AppendStr(&buf, ",");
-
- SQL->EscapeString(sql_handle, str, r->str);
- SQL->EscapeString(sql_handle, val, r->value);
-
- StrBuf->Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val);
+/**
+ * Handles save reg data from map server and distributes accordingly.
+ *
+ * @param val either str or int, depending on type
+ * @param type false when int, true otherwise
+ **/
+void inter_savereg(int account_id, int char_id, const char *key, unsigned int index, intptr_t val, bool is_string) {
+ /* to login server we go! */
+ if( key[0] == '#' && key[1] == '#' ) {/* global account reg */
+ global_accreg_to_login_add(key,index,val,is_string);
+ } else if ( key[0] == '#' ) {/* local account reg */
+ if( is_string ) {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", acc_reg_str_db, account_id, key, index, (char*)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", acc_reg_str_db, account_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
+ } else {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", acc_reg_num_db, account_id, key, index, (int)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", acc_reg_num_db, account_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
+ }
+ } else { /* char reg */
+ if( is_string ) {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", char_reg_str_db, char_id, key, index, (char*)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", char_reg_str_db, char_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
+ } else {
+ if( val ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`char_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", char_reg_num_db, char_id, key, index, (int)val) )
+ Sql_ShowDebug(sql_handle);
+ } else {
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", char_reg_num_db, char_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ }
}
}
-
- if( SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) ) {
- Sql_ShowDebug(sql_handle);
- }
-
- StrBuf->Destroy(&buf);
-
- return 1;
+
}
// Load account_reg from sql (type=2)
-int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type)
+int inter_accreg_fromsql(int account_id,int char_id, int fd, int type)
{
- struct global_reg* r;
char* data;
size_t len;
- int i;
+ unsigned int plen = 0;
- if( reg == NULL)
- return 0;
-
- memset(reg, 0, sizeof(struct accreg));
- reg->account_id = account_id;
- reg->char_id = char_id;
+ switch( type ) {
+ case 3: //char reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `char_id`='%d'", char_reg_str_db, char_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 2: //account reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", acc_reg_str_db, account_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 1: //account2 reg
+ ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
+ return 0;
+ default:
+ ShowError("inter_accreg_fromsql: Invalid type %d\n", type);
+ return 0;
+ }
+
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 1;/* is string type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+
+ /**
+ * Vessel!
+ *
+ * str type
+ * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) }
+ **/
+ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) {
+
+ SQL->GetData(sql_handle, 0, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ SQL->GetData(sql_handle, 1, &data, NULL);
+
+ WFIFOL(fd, plen) = (unsigned int)atol(data);
+ plen += 4;
+
+ SQL->GetData(sql_handle, 2, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ WFIFOW(fd, 14) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 1;/* is string type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+ }
+ }
+
+ /* mark & go. */
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- switch( type )
- {
- case 3: //char reg
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) )
- Sql_ShowDebug(sql_handle);
- break;
- case 2: //account reg
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) )
- Sql_ShowDebug(sql_handle);
- break;
- case 1: //account2 reg
- ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
- return 0;
- default:
- ShowError("inter_accreg_fromsql: Invalid type %d\n", type);
- return 0;
+ SQL->FreeResult(sql_handle);
+
+ switch( type ) {
+ case 3: //char reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `char_id`='%d'", char_reg_num_db, char_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 2: //account reg
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", acc_reg_num_db, account_id) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 1: //account2 reg
+ ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
+ return 0;
}
- for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i )
- {
- r = &reg->reg[i];
- // str
- SQL->GetData(sql_handle, 0, &data, &len);
- memcpy(r->str, data, min(len, sizeof(r->str)));
- // value
- SQL->GetData(sql_handle, 1, &data, &len);
- memcpy(r->value, data, min(len, sizeof(r->value)));
+
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 0;/* is int type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+
+ /**
+ * Vessel!
+ *
+ * int type
+ * { keyLength(B), key(<keyLength>), index(L), value(L) }
+ **/
+ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) {
+
+ SQL->GetData(sql_handle, 0, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ SQL->GetData(sql_handle, 1, &data, NULL);
+
+ WFIFOL(fd, plen) = (unsigned int)atol(data);
+ plen += 4;
+
+ SQL->GetData(sql_handle, 2, &data, NULL);
+
+ WFIFOL(fd, plen) = atoi(data);
+ plen += 4;
+
+ WFIFOW(fd, 14) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 0;/* is int type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+ }
}
- reg->reg_num = i;
+
+ /* mark as complete & go. */
+ WFIFOB(fd, 12) = type;
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
SQL->FreeResult(sql_handle);
return 1;
}
-// Initialize
-int inter_accreg_sql_init(void)
-{
- CREATE(accreg_pt, struct accreg, 1);
- return 0;
-
-}
-
/*==========================================
* read config file
*------------------------------------------*/
@@ -833,7 +930,6 @@ int inter_init_sql(const char *file)
inter_homunculus_sql_init();
inter_mercenary_sql_init();
inter_elemental_sql_init();
- inter_accreg_sql_init();
inter_mail_sql_init();
inter_auction_sql_init();
@@ -857,8 +953,6 @@ void inter_final(void)
inter_mail_sql_final();
inter_auction_sql_final();
- if (accreg_pt) aFree(accreg_pt);
-
do_final_msg();
return;
}
@@ -921,36 +1015,15 @@ int mapif_wis_end(struct WisData *wd, int flag)
}
// Account registry transfer to map-server
-static void mapif_account_reg(int fd, unsigned char *src)
-{
- WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO
- mapif_sendallwos(fd, src, WBUFW(src,2));
-}
+//static void mapif_account_reg(int fd, unsigned char *src)
+//{
+// WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO
+// mapif_sendallwos(fd, src, WBUFW(src,2));
+//}
// Send the requested account_reg
-int mapif_account_reg_reply(int fd,int account_id,int char_id, int type)
-{
- struct accreg *reg=accreg_pt;
- WFIFOHEAD(fd, 13 + 5000);
- inter_accreg_fromsql(account_id,char_id,reg,type);
-
- WFIFOW(fd,0)=0x3804;
- WFIFOL(fd,4)=account_id;
- WFIFOL(fd,8)=char_id;
- WFIFOB(fd,12)=type;
- if(reg->reg_num==0){
- WFIFOW(fd,2)=13;
- }else{
- int i,p;
- for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) {
- p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place.
- p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1;
- }
- WFIFOW(fd,2)=p;
- if (p>= 5000)
- ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id);
- }
- WFIFOSET(fd,WFIFOW(fd,2));
+int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) {
+ inter_accreg_fromsql(account_id,char_id,fd,type);
return 0;
}
@@ -1128,34 +1201,50 @@ int mapif_parse_WisToGM(int fd)
// Save account_reg into sql (type=2)
int mapif_parse_Registry(int fd)
{
- int j,p,len, max;
- struct accreg *reg=accreg_pt;
-
- memset(accreg_pt,0,sizeof(struct accreg));
- switch (RFIFOB(fd, 12)) {
- case 3: //Character registry
- max = GLOBAL_REG_NUM;
- break;
- case 2: //Account Registry
- max = ACCOUNT_REG_NUM;
- break;
- case 1: //Account2 registry, must be sent over to login server.
- return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4);
- default:
- return 1;
- }
- for(j=0,p=13;j<max && p<RFIFOW(fd,2);j++){
- sscanf((char*)RFIFOP(fd,p), "%31c%n",reg->reg[j].str,&len);
- reg->reg[j].str[len]='\0';
- p +=len+1; //+1 to skip the '\0' between strings.
- sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len);
- reg->reg[j].value[len]='\0';
- p +=len+1;
- }
- reg->reg_num=j;
+ int account_id = RFIFOL(fd, 4), char_id = RFIFOL(fd, 8), count = RFIFOW(fd, 12);
+
+ if( count ) {
+ int cursor = 14, i;
+ char key[32], sval[254];
+ unsigned int index;
+
+ global_accreg_to_login_start(account_id,char_id);
+
+ for(i = 0; i < count; i++) {
+ safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+
+ index = RFIFOL(fd, cursor);
+ cursor += 4;
+
+ switch (RFIFOB(fd, cursor++)) {
+ /* int */
+ case 0:
+ inter_savereg(account_id,char_id,key,index,RFIFOL(fd, cursor),false);
+ cursor += 4;
+ break;
+ case 1:
+ inter_savereg(account_id,char_id,key,index,0,false);
+ break;
+ /* str */
+ case 2:
+ safestrncpy(sval, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+ inter_savereg(account_id,char_id,key,index,(intptr_t)sval,true);
+ break;
+ case 3:
+ inter_savereg(account_id,char_id,key,index,0,true);
+ break;
+
+ default:
+ ShowError("mapif_parse_Registry: unknown type %d\n",RFIFOB(fd, cursor - 1));
+ return 1;
+ }
- inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12));
- mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers.
+ }
+
+ global_accreg_to_login_send();
+ }
return 0;
}
diff --git a/src/common/db.c b/src/common/db.c
index efe7ca8b2..ddfb032d4 100644
--- a/src/common/db.c
+++ b/src/common/db.c
@@ -47,6 +47,7 @@
* - create a db that organizes itself by splaying
*
* HISTORY:
+ * 2013/08/25 - Added int64/uint64 support for keys [Ind/Hercules]
* 2013/04/27 - Added ERS to speed up iterator memory allocation [Ind/Hercules]
* 2012/03/09 - Added enum for data types (int, uint, void*)
* 2008/02/19 - Fixed db_obj_get not handling deleted entries correctly.
@@ -236,10 +237,14 @@ static struct db_stats {
uint32 db_uint_alloc;
uint32 db_string_alloc;
uint32 db_istring_alloc;
+ uint32 db_int64_alloc;
+ uint32 db_uint64_alloc;
uint32 db_int_destroy;
uint32 db_uint_destroy;
uint32 db_string_destroy;
uint32 db_istring_destroy;
+ uint32 db_int64_destroy;
+ uint32 db_uint64_destroy;
// Function usage counters
uint32 db_rotate_left;
uint32 db_rotate_right;
@@ -256,10 +261,14 @@ static struct db_stats {
uint32 db_uint_cmp;
uint32 db_string_cmp;
uint32 db_istring_cmp;
+ uint32 db_int64_cmp;
+ uint32 db_uint64_cmp;
uint32 db_int_hash;
uint32 db_uint_hash;
uint32 db_string_hash;
uint32 db_istring_hash;
+ uint32 db_int64_hash;
+ uint32 db_uint64_hash;
uint32 db_release_nothing;
uint32 db_release_key;
uint32 db_release_data;
@@ -298,6 +307,8 @@ static struct db_stats {
uint32 db_i2key;
uint32 db_ui2key;
uint32 db_str2key;
+ uint32 db_i642key;
+ uint32 db_ui642key;
uint32 db_i2data;
uint32 db_ui2data;
uint32 db_ptr2data;
@@ -830,10 +841,14 @@ static void db_free_unlock(DBMap_impl* db)
* db_uint_cmp - Default comparator for DB_UINT databases. *
* db_string_cmp - Default comparator for DB_STRING databases. *
* db_istring_cmp - Default comparator for DB_ISTRING databases. *
+ * db_int64_cmp - Default comparator for DB_INT64 databases. *
+ * db_uint64_cmp - Default comparator for DB_UINT64 databases. *
* db_int_hash - Default hasher for DB_INT databases. *
* db_uint_hash - Default hasher for DB_UINT databases. *
* db_string_hash - Default hasher for DB_STRING databases. *
* db_istring_hash - Default hasher for DB_ISTRING databases. *
+ * db_int64_hash - Default hasher for DB_INT64 databases. *
+ * db_uint64_hash - Default hasher for DB_UINT64 databases. *
* db_release_nothing - Releaser that releases nothing. *
* db_release_key - Releaser that only releases the key. *
* db_release_data - Releaser that only releases the data. *
@@ -921,6 +936,51 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
}
/**
+ * Default comparator for DB_INT64 databases.
+ * Compares key1 to key2.
+ * Return 0 if equal, negative if lower and positive if higher.
+ * <code>maxlen</code> is ignored.
+ * @param key1 Key to be compared
+ * @param key2 Key being compared to
+ * @param maxlen Maximum length of the key to hash
+ * @return 0 if equal, negative if lower and positive if higher
+ * @see DBType#DB_INT64
+ * @see #DBComparator
+ * @see #db_default_cmp(DBType)
+ */
+static int db_int64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_int64_cmp);
+ if (key1.i64 < key2.i64) return -1;
+ if (key1.i64 > key2.i64) return 1;
+ return 0;
+}
+
+/**
+ * Default comparator for DB_UINT64 databases.
+ * Compares key1 to key2.
+ * Return 0 if equal, negative if lower and positive if higher.
+ * <code>maxlen</code> is ignored.
+ * @param key1 Key to be compared
+ * @param key2 Key being compared to
+ * @param maxlen Maximum length of the key to hash
+ * @return 0 if equal, negative if lower and positive if higher
+ * @see DBType#DB_UINT64
+ * @see #DBComparator
+ * @see #db_default_cmp(DBType)
+ */
+static int db_uint64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_uint64_cmp);
+ if (key1.ui64 < key2.ui64) return -1;
+ if (key1.ui64 > key2.ui64) return 1;
+ return 0;
+}
+
+
+/**
* Default hasher for DB_INT databases.
* Returns the value of the key as an unsigned int.
* <code>maxlen</code> is ignored.
@@ -931,11 +991,11 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @see #DBHasher
* @see #db_default_hash(DBType)
*/
-static unsigned int db_int_hash(DBKey key, unsigned short maxlen)
+static uint64 db_int_hash(DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_int_hash);
- return (unsigned int)key.i;
+ return (uint64)key.i;
}
/**
@@ -949,11 +1009,11 @@ static unsigned int db_int_hash(DBKey key, unsigned short maxlen)
* @see #DBHasher
* @see #db_default_hash(DBType)
*/
-static unsigned int db_uint_hash(DBKey key, unsigned short maxlen)
+static uint64 db_uint_hash(DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_uint_hash);
- return key.ui;
+ return (uint64)key.ui;
}
/**
@@ -965,7 +1025,7 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen)
* @see #DBHasher
* @see #db_default_hash(DBType)
*/
-static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
+static uint64 db_string_hash(DBKey key, unsigned short maxlen)
{
const char *k = key.str;
unsigned int hash = 0;
@@ -980,7 +1040,7 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
break;
}
- return hash;
+ return (uint64)hash;
}
/**
@@ -991,7 +1051,7 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
* @see DBType#DB_ISTRING
* @see #db_default_hash(DBType)
*/
-static unsigned int db_istring_hash(DBKey key, unsigned short maxlen)
+static uint64 db_istring_hash(DBKey key, unsigned short maxlen)
{
const char *k = key.str;
unsigned int hash = 0;
@@ -1006,7 +1066,43 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen)
break;
}
- return hash;
+ return (uint64)hash;
+}
+
+/**
+ * Default hasher for DB_INT64 databases.
+ * Returns the value of the key as an unsigned int.
+ * <code>maxlen</code> is ignored.
+ * @param key Key to be hashed
+ * @param maxlen Maximum length of the key to hash
+ * @return hash of the key
+ * @see DBType#DB_INT64
+ * @see #DBHasher
+ * @see #db_default_hash(DBType)
+ */
+static uint64 db_int64_hash(DBKey key, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_int64_hash);
+ return (uint64)key.i64;
+}
+
+/**
+ * Default hasher for DB_UINT64 databases.
+ * Just returns the value of the key.
+ * <code>maxlen</code> is ignored.
+ * @param key Key to be hashed
+ * @param maxlen Maximum length of the key to hash
+ * @return hash of the key
+ * @see DBType#DB_UINT64
+ * @see #DBHasher
+ * @see #db_default_hash(DBType)
+ */
+static uint64 db_uint64_hash(DBKey key, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_uint64_hash);
+ return key.ui64;
}
/**
@@ -2122,6 +2218,8 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args)
case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break;
case DB_STRING: DB_COUNTSTAT(db_string_destroy); break;
case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break;
+ case DB_INT64: DB_COUNTSTAT(db_int64_destroy); break;
+ case DB_UINT64: DB_COUNTSTAT(db_uint64_destroy); break;
}
#endif /* DB_ENABLE_STATS */
db_free_lock(db);
@@ -2246,6 +2344,8 @@ static DBOptions db_obj_options(DBMap* self)
* db_i2key - Manual cast from 'int' to 'DBKey'.
* db_ui2key - Manual cast from 'unsigned int' to 'DBKey'.
* db_str2key - Manual cast from 'unsigned char *' to 'DBKey'.
+ * db_i642key - Manual cast from 'int64' to 'DBKey'.
+ * db_ui642key - Manual cast from 'uin64' to 'DBKey'.
* db_i2data - Manual cast from 'int' to 'DBData'.
* db_ui2data - Manual cast from 'unsigned int' to 'DBData'.
* db_ptr2data - Manual cast from 'void*' to 'DBData'.
@@ -2272,7 +2372,9 @@ DBOptions db_fix_options(DBType type, DBOptions options)
DB_COUNTSTAT(db_fix_options);
switch (type) {
case DB_INT:
- case DB_UINT: // Numeric database, do nothing with the keys
+ case DB_UINT:
+ case DB_INT64:
+ case DB_UINT64: // Numeric database, do nothing with the keys
return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY));
default:
@@ -2292,6 +2394,8 @@ DBOptions db_fix_options(DBType type, DBOptions options)
* @see #db_uint_cmp(DBKey,DBKey,unsigned short)
* @see #db_string_cmp(DBKey,DBKey,unsigned short)
* @see #db_istring_cmp(DBKey,DBKey,unsigned short)
+ * @see #db_int64_cmp(DBKey,DBKey,unsigned short)
+ * @see #db_uint64_cmp(DBKey,DBKey,unsigned short)
*/
DBComparator db_default_cmp(DBType type)
{
@@ -2301,6 +2405,8 @@ DBComparator db_default_cmp(DBType type)
case DB_UINT: return &db_uint_cmp;
case DB_STRING: return &db_string_cmp;
case DB_ISTRING: return &db_istring_cmp;
+ case DB_INT64: return &db_int64_cmp;
+ case DB_UINT64: return &db_uint64_cmp;
default:
ShowError("db_default_cmp: Unknown database type %u\n", type);
return NULL;
@@ -2316,6 +2422,8 @@ DBComparator db_default_cmp(DBType type)
* @see #db_uint_hash(DBKey,unsigned short)
* @see #db_string_hash(DBKey,unsigned short)
* @see #db_istring_hash(DBKey,unsigned short)
+ * @see #db_int64_hash(DBKey,unsigned short)
+ * @see #db_uint64_hash(DBKey,unsigned short)
*/
DBHasher db_default_hash(DBType type)
{
@@ -2325,6 +2433,8 @@ DBHasher db_default_hash(DBType type)
case DB_UINT: return &db_uint_hash;
case DB_STRING: return &db_string_hash;
case DB_ISTRING: return &db_istring_hash;
+ case DB_INT64: return &db_int64_hash;
+ case DB_UINT64: return &db_uint64_hash;
default:
ShowError("db_default_hash: Unknown database type %u\n", type);
return NULL;
@@ -2412,6 +2522,8 @@ DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOpt
case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break;
case DB_STRING: DB_COUNTSTAT(db_string_alloc); break;
case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break;
+ case DB_INT64: DB_COUNTSTAT(db_int64_alloc); break;
+ case DB_UINT64: DB_COUNTSTAT(db_uint64_alloc); break;
}
#endif /* DB_ENABLE_STATS */
db = ers_alloc(db_alloc_ers, struct DBMap_impl);
@@ -2511,6 +2623,36 @@ DBKey db_str2key(const char *key)
}
/**
+ * Manual cast from 'int64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey db_i642key(int64 key)
+{
+ DBKey ret;
+
+ DB_COUNTSTAT(db_i642key);
+ ret.i64 = key;
+ return ret;
+}
+
+/**
+ * Manual cast from 'uin64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey db_ui642key(uint64 key)
+{
+ DBKey ret;
+
+ DB_COUNTSTAT(db_ui642key);
+ ret.ui64 = key;
+ return ret;
+}
+
+/**
* Manual cast from 'int' to the struct DBData.
* @param data Data to be casted
* @return The data as a DBData struct
@@ -2632,10 +2774,14 @@ void db_final(void)
"DB_UINT : allocated %10u, destroyed %10u\n"
"DB_STRING : allocated %10u, destroyed %10u\n"
"DB_ISTRING : allocated %10u, destroyed %10u\n",
+ "DB_INT64 : allocated %10u, destroyed %10u\n"
+ "DB_UINT64 : allocated %10u, destroyed %10u\n"
stats.db_int_alloc, stats.db_int_destroy,
stats.db_uint_alloc, stats.db_uint_destroy,
stats.db_string_alloc, stats.db_string_destroy,
- stats.db_istring_alloc, stats.db_istring_destroy);
+ stats.db_istring_alloc, stats.db_istring_destroy,
+ stats.db_int64_alloc, stats.db_int64_destroy,
+ stats.db_uint64_alloc, stats.db_uint64_destroy,);
ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n"
"db_rotate_left %10u, db_rotate_right %10u,\n"
"db_rebalance %10u, db_rebalance_erase %10u,\n"
@@ -2645,8 +2791,10 @@ void db_final(void)
"db_free_lock %10u, db_free_unlock %10u,\n"
"db_int_cmp %10u, db_uint_cmp %10u,\n"
"db_string_cmp %10u, db_istring_cmp %10u,\n"
+ "db_int64_cmp %10u, db_uint64_cmp %10u,\n"
"db_int_hash %10u, db_uint_hash %10u,\n"
"db_string_hash %10u, db_istring_hash %10u,\n"
+ "db_int64_hash %10u, db_uint64_hash %10u,\n"
"db_release_nothing %10u, db_release_key %10u,\n"
"db_release_data %10u, db_release_both %10u,\n"
"dbit_first %10u, dbit_last %10u,\n"
@@ -2666,6 +2814,7 @@ void db_final(void)
"db_default_release %10u, db_custom_release %10u,\n"
"db_alloc %10u, db_i2key %10u,\n"
"db_ui2key %10u, db_str2key %10u,\n"
+ "db_i642key %10u, db_ui642key %10u,\n"
"db_i2data %10u, db_ui2data %10u,\n"
"db_ptr2data %10u, db_data2i %10u,\n"
"db_data2ui %10u, db_data2ptr %10u,\n"
@@ -2678,8 +2827,10 @@ void db_final(void)
stats.db_free_lock, stats.db_free_unlock,
stats.db_int_cmp, stats.db_uint_cmp,
stats.db_string_cmp, stats.db_istring_cmp,
+ stats.db_int64_cmp, stats.db_uint64_cmp,
stats.db_int_hash, stats.db_uint_hash,
stats.db_string_hash, stats.db_istring_hash,
+ stats.db_int64_hash, stats.db_uint64_hash,
stats.db_release_nothing, stats.db_release_key,
stats.db_release_data, stats.db_release_both,
stats.dbit_first, stats.dbit_last,
@@ -2699,6 +2850,7 @@ void db_final(void)
stats.db_default_release, stats.db_custom_release,
stats.db_alloc, stats.db_i2key,
stats.db_ui2key, stats.db_str2key,
+ stats.db_i642key, stats.db_ui642key,
stats.db_i2data, stats.db_ui2data,
stats.db_ptr2data, stats.db_data2i,
stats.db_data2ui, stats.db_data2ptr,
@@ -2855,4 +3007,7 @@ void db_defaults(void) {
DB->str2key = db_str2key;
DB->ui2data = db_ui2data;
DB->ui2key = db_ui2key;
+ DB->i642key = db_i642key;
+ DB->ui642key = db_ui642key;
+
}
diff --git a/src/common/db.h b/src/common/db.h
index 5f4478909..9d7bdda10 100644
--- a/src/common/db.h
+++ b/src/common/db.h
@@ -20,6 +20,7 @@
* - see what functions need or should be added to the database interface *
* *
* HISTORY: *
+ * 2013/08/25 - Added int64/uint64 support for keys *
* 2012/03/09 - Added enum for data types (int, uint, void*) *
* 2007/11/09 - Added an iterator to the database. *
* 2.1 (Athena build #???#) - Portability fix *
@@ -83,6 +84,8 @@ typedef enum DBRelease {
* @param DB_UINT Uses unsigned int's for keys
* @param DB_STRING Uses strings for keys.
* @param DB_ISTRING Uses case insensitive strings for keys.
+ * @param DB_INT64 Uses int64's for keys
+ * @param DB_UINT64 Uses uint64's for keys
* @public
* @see #DBOptions
* @see #DBKey
@@ -96,7 +99,9 @@ typedef enum DBType {
DB_INT,
DB_UINT,
DB_STRING,
- DB_ISTRING
+ DB_ISTRING,
+ DB_INT64,
+ DB_UINT64,
} DBType;
/**
@@ -145,6 +150,8 @@ typedef union DBKey {
int i;
unsigned int ui;
const char *str;
+ int64 i64;
+ uint64 ui64;
} DBKey;
/**
@@ -158,7 +165,7 @@ typedef union DBKey {
typedef enum DBDataType {
DB_DATA_INT,
DB_DATA_UINT,
- DB_DATA_PTR
+ DB_DATA_PTR,
} DBDataType;
/**
@@ -245,7 +252,7 @@ typedef int (*DBComparator)(DBKey key1, DBKey key2, unsigned short maxlen);
* @public
* @see #db_default_hash(DBType)
*/
-typedef unsigned int (*DBHasher)(DBKey key, unsigned short maxlen);
+typedef uint64 (*DBHasher)(DBKey key, unsigned short maxlen);
/**
* Format of the releaser used by the database system.
@@ -598,65 +605,86 @@ struct DBMap {
// For easy access to the common functions.
-#define db_exists(db,k) ( (db)->exists((db),(k)) )
-#define idb_exists(db,k) ( (db)->exists((db),DB->i2key(k)) )
-#define uidb_exists(db,k) ( (db)->exists((db),DB->ui2key(k)) )
-#define strdb_exists(db,k) ( (db)->exists((db),DB->str2key(k)) )
+#define db_exists(db,k) ( (db)->exists((db),(k)) )
+#define idb_exists(db,k) ( (db)->exists((db),DB->i2key(k)) )
+#define uidb_exists(db,k) ( (db)->exists((db),DB->ui2key(k)) )
+#define strdb_exists(db,k) ( (db)->exists((db),DB->str2key(k)) )
+#define i64db_exists(db,k) ( (db)->exists((db),DB->i642key(k)) )
+#define ui64db_exists(db,k) ( (db)->exists((db),DB->ui642key(k)) )
// Get pointer-type data from DBMaps of various key types
-#define db_get(db,k) ( DB->data2ptr((db)->get((db),(k))) )
-#define idb_get(db,k) ( DB->data2ptr((db)->get((db),DB->i2key(k))) )
-#define uidb_get(db,k) ( DB->data2ptr((db)->get((db),DB->ui2key(k))) )
-#define strdb_get(db,k) ( DB->data2ptr((db)->get((db),DB->str2key(k))) )
+#define db_get(db,k) ( DB->data2ptr((db)->get((db),(k))) )
+#define idb_get(db,k) ( DB->data2ptr((db)->get((db),DB->i2key(k))) )
+#define uidb_get(db,k) ( DB->data2ptr((db)->get((db),DB->ui2key(k))) )
+#define strdb_get(db,k) ( DB->data2ptr((db)->get((db),DB->str2key(k))) )
+#define i64db_get(db,k) ( DB->data2ptr((db)->get((db),DB->i642key(k))) )
+#define ui64db_get(db,k) ( DB->data2ptr((db)->get((db),DB->ui642key(k))) )
+
// Get int-type data from DBMaps of various key types
-#define db_iget(db,k) ( DB->data2i((db)->get((db),(k))) )
-#define idb_iget(db,k) ( DB->data2i((db)->get((db),DB->i2key(k))) )
-#define uidb_iget(db,k) ( DB->data2i((db)->get((db),DB->ui2key(k))) )
-#define strdb_iget(db,k) ( DB->data2i((db)->get((db),DB->str2key(k))) )
+#define db_iget(db,k) ( DB->data2i((db)->get((db),(k))) )
+#define idb_iget(db,k) ( DB->data2i((db)->get((db),DB->i2key(k))) )
+#define uidb_iget(db,k) ( DB->data2i((db)->get((db),DB->ui2key(k))) )
+#define strdb_iget(db,k) ( DB->data2i((db)->get((db),DB->str2key(k))) )
+#define i64db_iget(db,k) ( DB->data2i((db)->get((db),DB->i642key(k))) )
+#define ui64db_iget(db,k) ( DB->data2i((db)->get((db),DB->ui642key(k))) )
// Get uint-type data from DBMaps of various key types
-#define db_uiget(db,k) ( DB->data2ui((db)->get((db),(k))) )
-#define idb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->i2key(k))) )
-#define uidb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->ui2key(k))) )
-#define strdb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->str2key(k))) )
+#define db_uiget(db,k) ( DB->data2ui((db)->get((db),(k))) )
+#define idb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->i2key(k))) )
+#define uidb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->ui2key(k))) )
+#define strdb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->str2key(k))) )
+#define i64db_uiget(db,k) ( DB->data2ui((db)->get((db),DB->i642key(k))) )
+#define ui64db_uiget(db,k) ( DB->data2ui((db)->get((db),DB->ui642key(k))) )
// Put pointer-type data into DBMaps of various key types
-#define db_put(db,k,d) ( (db)->put((db),(k),DB->ptr2data(d),NULL) )
-#define idb_put(db,k,d) ( (db)->put((db),DB->i2key(k),DB->ptr2data(d),NULL) )
-#define uidb_put(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->ptr2data(d),NULL) )
-#define strdb_put(db,k,d) ( (db)->put((db),DB->str2key(k),DB->ptr2data(d),NULL) )
+#define db_put(db,k,d) ( (db)->put((db),(k),DB->ptr2data(d),NULL) )
+#define idb_put(db,k,d) ( (db)->put((db),DB->i2key(k),DB->ptr2data(d),NULL) )
+#define uidb_put(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->ptr2data(d),NULL) )
+#define strdb_put(db,k,d) ( (db)->put((db),DB->str2key(k),DB->ptr2data(d),NULL) )
+#define i64db_put(db,k,d) ( (db)->put((db),DB->i642key(k),DB->ptr2data(d),NULL) )
+#define ui64db_put(db,k,d) ( (db)->put((db),DB->ui642key(k),DB->ptr2data(d),NULL) )
// Put int-type data into DBMaps of various key types
-#define db_iput(db,k,d) ( (db)->put((db),(k),DB->i2data(d),NULL) )
-#define idb_iput(db,k,d) ( (db)->put((db),DB->i2key(k),DB->i2data(d),NULL) )
-#define uidb_iput(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->i2data(d),NULL) )
-#define strdb_iput(db,k,d) ( (db)->put((db),DB->str2key(k),DB->i2data(d),NULL) )
+#define db_iput(db,k,d) ( (db)->put((db),(k),DB->i2data(d),NULL) )
+#define idb_iput(db,k,d) ( (db)->put((db),DB->i2key(k),DB->i2data(d),NULL) )
+#define uidb_iput(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->i2data(d),NULL) )
+#define strdb_iput(db,k,d) ( (db)->put((db),DB->str2key(k),DB->i2data(d),NULL) )
+#define i64db_iput(db,k,d) ( (db)->put((db),DB->i642key(k),DB->i2data(d),NULL) )
+#define ui64db_iput(db,k,d) ( (db)->put((db),DB->ui642key(k),DB->i2data(d),NULL) )
// Put uint-type data into DBMaps of various key types
-#define db_uiput(db,k,d) ( (db)->put((db),(k),DB->ui2data(d),NULL) )
-#define idb_uiput(db,k,d) ( (db)->put((db),DB->i2key(k),DB->ui2data(d),NULL) )
-#define uidb_uiput(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->ui2data(d),NULL) )
-#define strdb_uiput(db,k,d) ( (db)->put((db),DB->str2key(k),DB->ui2data(d),NULL) )
+#define db_uiput(db,k,d) ( (db)->put((db),(k),DB->ui2data(d),NULL) )
+#define idb_uiput(db,k,d) ( (db)->put((db),DB->i2key(k),DB->ui2data(d),NULL) )
+#define uidb_uiput(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->ui2data(d),NULL) )
+#define strdb_uiput(db,k,d) ( (db)->put((db),DB->str2key(k),DB->ui2data(d),NULL) )
+#define i64db_uiput(db,k,d) ( (db)->put((db),DB->i642key(k),DB->ui2data(d),NULL) )
+#define ui64db_uiput(db,k,d) ( (db)->put((db),DB->ui642key(k),DB->ui2data(d),NULL) )
// Remove entry from DBMaps of various key types
-#define db_remove(db,k) ( (db)->remove((db),(k),NULL) )
-#define idb_remove(db,k) ( (db)->remove((db),DB->i2key(k),NULL) )
-#define uidb_remove(db,k) ( (db)->remove((db),DB->ui2key(k),NULL) )
-#define strdb_remove(db,k) ( (db)->remove((db),DB->str2key(k),NULL) )
+#define db_remove(db,k) ( (db)->remove((db),(k),NULL) )
+#define idb_remove(db,k) ( (db)->remove((db),DB->i2key(k),NULL) )
+#define uidb_remove(db,k) ( (db)->remove((db),DB->ui2key(k),NULL) )
+#define strdb_remove(db,k) ( (db)->remove((db),DB->str2key(k),NULL) )
+#define i64db_remove(db,k) ( (db)->remove((db),DB->i642key(k),NULL) )
+#define ui64db_remove(db,k) ( (db)->remove((db),DB->ui642key(k),NULL) )
//These are discarding the possible vargs you could send to the function, so those
//that require vargs must not use these defines.
-#define db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),(k),(f))) )
-#define idb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->i2key(k),(f))) )
-#define uidb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->ui2key(k),(f))) )
-#define strdb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->str2key(k),(f))) )
+#define db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),(k),(f))) )
+#define idb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->i2key(k),(f))) )
+#define uidb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->ui2key(k),(f))) )
+#define strdb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->str2key(k),(f))) )
+#define i64db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->i642key(k),(f))) )
+#define ui64db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->ui642key(k),(f))) )
// Database creation and destruction macros
#define idb_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_INT,(opt),sizeof(int))
#define uidb_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_UINT,(opt),sizeof(unsigned int))
#define strdb_alloc(opt,maxlen) DB->alloc(__FILE__,__func__,__LINE__,DB_STRING,(opt),(maxlen))
#define stridb_alloc(opt,maxlen) DB->alloc(__FILE__,__func__,__LINE__,DB_ISTRING,(opt),(maxlen))
+#define i64db_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_INT64,(opt),sizeof(int64))
+#define ui64db_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_UINT64,(opt),sizeof(uint64))
#define db_destroy(db) ( (db)->destroy((db),NULL) )
// Other macros
#define db_clear(db) ( (db)->clear((db),NULL) )
@@ -682,6 +710,8 @@ struct DBMap {
* db_i2key - Manual cast from 'int' to 'DBKey'. *
* db_ui2key - Manual cast from 'unsigned int' to 'DBKey'. *
* db_str2key - Manual cast from 'unsigned char *' to 'DBKey'. *
+ * db_i642key - Manual cast from 'int64' to 'DBKey'. *
+ * db_ui642key - Manual cast from 'uint64' to 'DBKey'. *
* db_i2data - Manual cast from 'int' to 'DBData'. *
* db_ui2data - Manual cast from 'unsigned int' to 'DBData'. *
* db_ptr2data - Manual cast from 'void*' to 'DBData'. *
@@ -803,6 +833,22 @@ DBKey (*ui2key) (unsigned int key);
DBKey (*str2key) (const char *key);
/**
+ * Manual cast from 'int64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey (*i642key) (int64 key);
+
+/**
+ * Manual cast from 'uint64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey (*ui642key) (uint64 key);
+
+/**
* Manual cast from 'int' to the struct DBData.
* @param data Data to be casted
* @return The data as a DBData struct
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 273edc42b..594d1cb26 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -101,11 +101,6 @@
//Update this max as necessary. 55 is the value needed for Super Baby currently
//Raised to 84 since Expanded Super Novice needs it.
#define MAX_SKILL_TREE 84
-#define GLOBAL_REG_NUM 256 // Max permanent character variables per char
-#define ACCOUNT_REG_NUM 64 // Max permanent local account variables per account
-#define ACCOUNT_REG2_NUM 16 // Max permanent global account variables per account
-//Should hold the max of GLOBAL/ACCOUNT/ACCOUNT2 (needed for some arrays that hold all three)
-#define MAX_REG_NUM 256
#define DEFAULT_WALK_SPEED 150
#define MIN_WALK_SPEED 20 /* below 20 clips animation */
#define MAX_WALK_SPEED 1000
@@ -269,16 +264,19 @@ struct s_skill {
unsigned char flag; // See enum e_skill_flag
};
-struct global_reg {
- char str[32];
- char value[256];
+struct script_reg_state {
+ unsigned int type : 1;/* because I'm a memory hoarder and having them in the same struct would be a 8-byte/instance waste while ints outnumber str on a 10000-to-1 ratio. */
+ unsigned int update : 1;/* whether it needs to be sent to char server for insertion/update/delete */
};
-// Holds array of global registries, used by the char server and converter.
-struct accreg {
- int account_id, char_id;
- int reg_num;
- struct global_reg reg[MAX_REG_NUM];
+struct script_reg_num {
+ struct script_reg_state flag;
+ int value;
+};
+
+struct script_reg_str {
+ struct script_reg_state flag;
+ char *value;
};
// For saving status changes across sessions. [Skotlex]
@@ -483,15 +481,6 @@ struct auction_data {
int auction_end_timer;
};
-struct registry {
- int global_num;
- struct global_reg global[GLOBAL_REG_NUM];
- int account_num;
- struct global_reg account[ACCOUNT_REG_NUM];
- int account2_num;
- struct global_reg account2[ACCOUNT_REG2_NUM];
-};
-
struct party_member {
int account_id;
int char_id;
@@ -866,6 +855,14 @@ enum e_char_server_type {
CST_F2P = 4,
};
+enum e_pc_reg_loading {
+ PRL_NONE = 0x0,
+ PRL_CHAR = 0x1,
+ PRL_ACCL = 0x2,/* local */
+ PRL_ACCG = 0x4,/* global */
+ PRL_ALL = 0xFF,
+};
+
/* packet size constant for itemlist */
#if MAX_INVENTORY > MAX_STORAGE && MAX_INVENTORY > MAX_CART
#define MAX_ITEMLIST MAX_INVENTORY
diff --git a/src/common/socket.c b/src/common/socket.c
index 9c6938008..1ffa15708 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -1464,8 +1464,6 @@ void socket_datasync(int fd, bool send) {
{ sizeof(struct item) },
{ sizeof(struct point) },
{ sizeof(struct s_skill) },
- { sizeof(struct global_reg) },
- { sizeof(struct accreg) },
{ sizeof(struct status_change_data) },
{ sizeof(struct storage_data) },
{ sizeof(struct guild_storage) },
@@ -1476,7 +1474,6 @@ void socket_datasync(int fd, bool send) {
{ sizeof(struct s_friend) },
{ sizeof(struct mail_message) },
{ sizeof(struct mail_data) },
- { sizeof(struct registry) },
{ sizeof(struct party_member) },
{ sizeof(struct party) },
{ sizeof(struct guild_member) },
@@ -1487,6 +1484,7 @@ void socket_datasync(int fd, bool send) {
{ sizeof(struct guild) },
{ sizeof(struct guild_castle) },
{ sizeof(struct fame_list) },
+ { PACKETVER },
};
unsigned short i;
unsigned int alen = ARRAYLENGTH(data_list);
diff --git a/src/login/account.h b/src/login/account.h
index f55e38b0c..74a9e9626 100644
--- a/src/login/account.h
+++ b/src/login/account.h
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#ifndef __ACCOUNT_H_INCLUDED__
#define __ACCOUNT_H_INCLUDED__
@@ -32,8 +33,6 @@ struct mmo_account
char lastlogin[24]; // date+time of last successful login
char last_ip[16]; // save of last IP of connection
char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00)
- int account_reg2_num;
- struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server)
};
@@ -137,4 +136,7 @@ struct AccountDB
Sql *account_db_sql_up(AccountDB* self);
+void mmo_send_accreg2(AccountDB* self, int fd, int account_id, int char_id);
+void mmo_save_accreg2(AccountDB* self, int fd, int account_id, int char_id);
+
#endif // __ACCOUNT_H_INCLUDED__
diff --git a/src/login/account_sql.c b/src/login/account_sql.c
index 283eb3a0d..1483196ab 100644
--- a/src/login/account_sql.c
+++ b/src/login/account_sql.c
@@ -9,6 +9,7 @@
#include "../common/strlib.h"
#include "../common/timer.h"
#include "../common/console.h"
+#include "../common/socket.h"
#include "account.h"
#include <stdlib.h>
#include <string.h>
@@ -40,7 +41,9 @@ typedef struct AccountDB_SQL
// other settings
bool case_sensitive;
char account_db[32];
- char accreg_db[32];
+ char global_acc_reg_num_db[32];
+ char global_acc_reg_str_db[32];
+
} AccountDB_SQL;
@@ -106,7 +109,8 @@ AccountDB* account_db_sql(void)
// other settings
db->case_sensitive = false;
safestrncpy(db->account_db, "login", sizeof(db->account_db));
- safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db));
+ safestrncpy(db->global_acc_reg_num_db, "global_acc_reg_num_db", sizeof(db->global_acc_reg_num_db));
+ safestrncpy(db->global_acc_reg_str_db, "global_acc_reg_str_db", sizeof(db->global_acc_reg_str_db));
return &db->vtable;
}
@@ -250,8 +254,11 @@ static bool account_db_sql_get_property(AccountDB* self, const char* key, char*
if( strcmpi(key, "account_db") == 0 )
safesnprintf(buf, buflen, "%s", db->account_db);
else
- if( strcmpi(key, "accreg_db") == 0 )
- safesnprintf(buf, buflen, "%s", db->accreg_db);
+ if( strcmpi(key, "global_acc_reg_str_db") == 0 )
+ safesnprintf(buf, buflen, "%s", db->global_acc_reg_str_db);
+ else
+ if( strcmpi(key, "global_acc_reg_num_db") == 0 )
+ safesnprintf(buf, buflen, "%s", db->global_acc_reg_num_db);
else
return false;// not found
return true;
@@ -321,8 +328,11 @@ static bool account_db_sql_set_property(AccountDB* self, const char* key, const
if( strcmpi(key, "account_db") == 0 )
safestrncpy(db->account_db, value, sizeof(db->account_db));
else
- if( strcmpi(key, "accreg_db") == 0 )
- safestrncpy(db->accreg_db, value, sizeof(db->accreg_db));
+ if( strcmpi(key, "global_acc_reg_str_db") == 0 )
+ safestrncpy(db->global_acc_reg_str_db, value, sizeof(db->global_acc_reg_str_db));
+ else
+ if( strcmpi(key, "global_acc_reg_num_db") == 0 )
+ safestrncpy(db->global_acc_reg_num_db, value, sizeof(db->global_acc_reg_num_db));
else
return false;// not found
return true;
@@ -393,7 +403,9 @@ static bool account_db_sql_remove(AccountDB* self, const int account_id)
if( SQL_SUCCESS != SQL->QueryStr(sql_handle, "START TRANSACTION")
|| SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id)
- || SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) )
+ || SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->global_acc_reg_num_db, account_id)
+ || SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->global_acc_reg_str_db, account_id)
+ )
Sql_ShowDebug(sql_handle);
else
result = true;
@@ -520,7 +532,6 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
{
Sql* sql_handle = db->accounts;
char* data;
- int i = 0;
// retrieve login entry for the specified account
if( SQL_ERROR == SQL->Query(sql_handle,
@@ -556,27 +567,6 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
SQL->FreeResult(sql_handle);
-
- // retrieve account regs for the specified user
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
- {
- Sql_ShowDebug(sql_handle);
- return false;
- }
-
- acc->account_reg2_num = (int)SQL->NumRows(sql_handle);
-
- while( SQL_SUCCESS == SQL->NextRow(sql_handle) )
- {
- SQL->GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str));
- SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value));
- ++i;
- }
- SQL->FreeResult(sql_handle);
-
- if( i != acc->account_reg2_num )
- return false;
-
return true;
}
@@ -585,7 +575,6 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
Sql* sql_handle = db->accounts;
SqlStmt* stmt = SQL->StmtMalloc(sql_handle);
bool result = false;
- int i;
// try
do
@@ -647,34 +636,6 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
}
}
- // remove old account regs
- if( SQL_SUCCESS != SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
- {
- Sql_ShowDebug(sql_handle);
- break;
- }
- // insert new account regs
- if( SQL_SUCCESS != SQL->StmtPrepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id) )
- {
- SqlStmt_ShowDebug(stmt);
- break;
- }
- for( i = 0; i < acc->account_reg2_num; ++i )
- {
- if( SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str))
- || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value))
- || SQL_SUCCESS != SQL->StmtExecute(stmt)
- ) {
- SqlStmt_ShowDebug(stmt);
- break;
- }
- }
- if( i < acc->account_reg2_num )
- {
- result = false;
- break;
- }
-
// if we got this far, everything was successful
result = true;
@@ -686,6 +647,7 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
return result;
}
+
Sql* account_db_sql_up(AccountDB* self) {
AccountDB_SQL* db = (AccountDB_SQL*)self;
Sql_HerculesUpdateCheck(db->accounts);
@@ -694,3 +656,196 @@ Sql* account_db_sql_up(AccountDB* self) {
#endif
return db->accounts;
}
+void mmo_save_accreg2(AccountDB* self, int fd, int account_id, int char_id) {
+ Sql* sql_handle = ((AccountDB_SQL*)self)->accounts;
+ AccountDB_SQL* db = (AccountDB_SQL*)self;
+ int count = RFIFOW(fd, 12);
+
+ if( count ) {
+ int cursor = 14, i;
+ char key[32], sval[254];
+ unsigned int index;
+
+ for(i = 0; i < count; i++) {
+ safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+
+ index = RFIFOL(fd, cursor);
+ cursor += 4;
+
+ switch (RFIFOB(fd, cursor++)) {
+ /* int */
+ case 0:
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%d')", db->global_acc_reg_num_db, account_id, key, index, RFIFOL(fd, cursor)) )
+ Sql_ShowDebug(sql_handle);
+ cursor += 4;
+ break;
+ case 1:
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", db->global_acc_reg_num_db, account_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ /* str */
+ case 2:
+ safestrncpy(sval, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", db->global_acc_reg_str_db, account_id, key, index, sval) )
+ Sql_ShowDebug(sql_handle);
+ break;
+ case 3:
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `key` = '%s' AND `index` = '%u' LIMIT 1", db->global_acc_reg_str_db, account_id, key, index) )
+ Sql_ShowDebug(sql_handle);
+ break;
+
+ default:
+ ShowError("mmo_save_accreg2: DA HOO UNKNOWN TYPE %d\n",RFIFOB(fd, cursor - 1));
+ return;
+ }
+
+ }
+
+ }
+
+}
+void mmo_send_accreg2(AccountDB* self, int fd, int account_id, int char_id) {
+ Sql* sql_handle = ((AccountDB_SQL*)self)->accounts;
+ AccountDB_SQL* db = (AccountDB_SQL*)self;
+ char* data;
+ int plen = 0;
+ size_t len;
+
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_str_db, account_id) )
+ Sql_ShowDebug(sql_handle);
+
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 1;/* is string type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+
+ /**
+ * Vessel!
+ *
+ * str type
+ * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) }
+ **/
+ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) {
+
+ SQL->GetData(sql_handle, 0, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ SQL->GetData(sql_handle, 1, &data, NULL);
+
+ WFIFOL(fd, plen) = (unsigned int)atol(data);
+ plen += 4;
+
+ SQL->GetData(sql_handle, 2, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ WFIFOW(fd, 14) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 1;/* is string type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+ }
+ }
+
+ /* mark & go. */
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ SQL->FreeResult(sql_handle);
+
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_num_db, account_id) )
+ Sql_ShowDebug(sql_handle);
+
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 0;/* is int type */
+ WFIFOW(fd, 14) = 0;/* count */
+ plen = 16;
+
+ /**
+ * Vessel!
+ *
+ * int type
+ * { keyLength(B), key(<keyLength>), index(L), value(L) }
+ **/
+ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) {
+
+ SQL->GetData(sql_handle, 0, &data, NULL);
+ len = strlen(data)+1;
+
+ WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(fd,plen), data, len);
+ plen += len;
+
+ SQL->GetData(sql_handle, 1, &data, NULL);
+
+ WFIFOL(fd, plen) = (unsigned int)atol(data);
+ plen += 4;
+
+ SQL->GetData(sql_handle, 2, &data, NULL);
+
+ WFIFOL(fd, plen) = atoi(data);
+ plen += 4;
+
+ WFIFOW(fd, 14) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(fd, 60000 + 300);
+ WFIFOW(fd, 0) = 0x3804;
+ /* 0x2 = length, set prior to being sent */
+ WFIFOL(fd, 4) = account_id;
+ WFIFOL(fd, 8) = char_id;
+ WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */
+ WFIFOB(fd, 13) = 0;/* is int type */
+ WFIFOW(fd, 14) = 0;/* count */
+
+ plen = 16;
+ }
+ }
+
+ /* mark as complete & go. */
+ WFIFOB(fd, 12) = 1;
+ WFIFOW(fd, 2) = plen;
+ WFIFOSET(fd, plen);
+
+ SQL->FreeResult(sql_handle);
+}
diff --git a/src/login/login.c b/src/login/login.c
index 57a2d0b74..e9d0eac9d 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -704,30 +704,8 @@ int parse_fromchar(int fd)
if( !accounts->load_num(accounts, &acc, account_id) )
ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
- else
- {
- int len;
- int p;
- ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip);
- for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j )
- {
- sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len);
- acc.account_reg2[j].str[len]='\0';
- p +=len+1; //+1 to skip the '\0' between strings.
- sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len);
- acc.account_reg2[j].value[len]='\0';
- p +=len+1;
- remove_control_chars(acc.account_reg2[j].str);
- remove_control_chars(acc.account_reg2[j].value);
- }
- acc.account_reg2_num = j;
-
- // Save
- accounts->save(accounts, &acc);
-
- // Sending information towards the other char-servers.
- RFIFOW(fd,0) = 0x2729;// reusing read buffer
- charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2));
+ else {
+ mmo_save_accreg2(accounts,fd,account_id,RFIFOL(fd, 8));
}
RFIFOSKIP(fd,RFIFOW(fd,2));
}
@@ -797,34 +775,11 @@ int parse_fromchar(int fd)
if (RFIFOREST(fd) < 10)
return 0;
{
- struct mmo_account acc;
- size_t off;
-
int account_id = RFIFOL(fd,2);
int char_id = RFIFOL(fd,6);
RFIFOSKIP(fd,10);
- WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg));
- WFIFOW(fd,0) = 0x2729;
- WFIFOL(fd,4) = account_id;
- WFIFOL(fd,8) = char_id;
- WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
-
- off = 13;
- if( accounts->load_num(accounts, &acc, account_id) )
- {
- for( j = 0; j < acc.account_reg2_num; j++ )
- {
- if( acc.account_reg2[j].str[0] != '\0' )
- {
- off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place.
- off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1;
- }
- }
- }
-
- WFIFOW(fd,2) = (uint16)off;
- WFIFOSET(fd,WFIFOW(fd,2));
+ mmo_send_accreg2(accounts,fd,account_id,char_id);
}
break;
diff --git a/src/login/login.h b/src/login/login.h
index 80cbee74b..d6a021125 100644
--- a/src/login/login.h
+++ b/src/login/login.h
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#ifndef _LOGIN_H_
#define _LOGIN_H_
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index ffd6da9d5..d4b6c2382 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -8444,12 +8444,12 @@ ACMD(set) {
break;
case '#':
if( reg[1] == '#' )
- data->u.str = pc_readaccountreg2str(sd, reg);// global
+ data->u.str = pc_readaccountreg2str(sd, script->add_str(reg));// global
else
- data->u.str = pc_readaccountregstr(sd, reg);// local
+ data->u.str = pc_readaccountregstr(sd, script->add_str(reg));// local
break;
default:
- data->u.str = pc_readglobalreg_str(sd, reg);
+ data->u.str = pc_readglobalreg_str(sd, script->add_str(reg));
break;
}
@@ -8473,12 +8473,12 @@ ACMD(set) {
break;
case '#':
if( reg[1] == '#' )
- data->u.num = pc_readaccountreg2(sd, reg);// global
+ data->u.num = pc_readaccountreg2(sd, script->add_str(reg));// global
else
- data->u.num = pc_readaccountreg(sd, reg);// local
+ data->u.num = pc_readaccountreg(sd, script->add_str(reg));// local
break;
default:
- data->u.num = pc_readglobalreg(sd, reg);
+ data->u.num = pc_readglobalreg(sd, script->add_str(reg));
break;
}
diff --git a/src/map/battleground.c b/src/map/battleground.c
index 6029a8c35..96d39aa45 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -496,7 +496,7 @@ void bg_match_over(struct bg_arena *arena, bool canceled) {
if( canceled )
clif->colormes(sd->fd,COLOR_RED,"BG Match Cancelled: not enough players");
else {
- pc_setglobalreg(sd, arena->delay_var, (unsigned int)time(NULL));
+ pc_setglobalreg(sd, script->add_str(arena->delay_var), (unsigned int)time(NULL));
}
}
}
@@ -693,7 +693,7 @@ enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_
tsec = (unsigned int)time(NULL);
- if ( ( tick = pc_readglobalreg(sd, bg->gdelay_var) ) && tsec < tick ) {
+ if ( ( tick = pc_readglobalreg(sd, script->add_str(bg->gdelay_var)) ) && tsec < tick ) {
char response[100];
if( (tick-tsec) > 60 )
sprintf(response, "You are a deserter! Wait %d minute(s) before you can apply again",(tick-tsec)/60);
@@ -703,7 +703,7 @@ enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_
return BGQA_FAIL_DESERTER;
}
- if ( ( tick = pc_readglobalreg(sd, arena->delay_var) ) && tsec < tick ) {
+ if ( ( tick = pc_readglobalreg(sd, script->add_str(arena->delay_var)) ) && tsec < tick ) {
char response[100];
if( (tick-tsec) > 60 )
sprintf(response, "You can't reapply to this arena so fast. Apply to the different arena or wait %d minute(s)",(tick-tsec)/60);
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 7b5cbbe59..d66ec1d85 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -265,12 +265,8 @@ int chrif_save(struct map_session_data *sd, int flag) {
sd->state.storage_flag = 0; //Force close it.
//Saving of registry values.
- if (sd->state.reg_dirty&4)
- intif->saveregistry(sd, 3); //Save char regs
- if (sd->state.reg_dirty&2)
- intif->saveregistry(sd, 2); //Save account regs
- if (sd->state.reg_dirty&1)
- intif->saveregistry(sd, 1); //Save account2 regs
+ if (sd->vars_dirty)
+ intif->saveregistry(sd);
WFIFOHEAD(chrif->fd, sizeof(sd->status) + 13);
WFIFOW(chrif->fd,0) = 0x2b01;
@@ -603,7 +599,7 @@ void chrif_authok(int fd) {
//Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth.
if ( ( sd = map->id2sd(account_id) ) != NULL )
return;
-
+
if ( ( node = chrif->search(account_id) ) == NULL )
return; // should not happen
diff --git a/src/map/clif.c b/src/map/clif.c
index 4ae6c8d34..5f61bafad 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -14419,7 +14419,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd)
sd->feel_map[i].index = map_id2index(sd->bl.m);
sd->feel_map[i].m = sd->bl.m;
- pc_setglobalreg(sd,pc->sg_info[i].feel_var,sd->feel_map[i].index);
+ pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),sd->feel_map[i].index);
//Are these really needed? Shouldn't they show up automatically from the feel save packet?
// clif_misceffect2(&sd->bl, 0x1b0);
diff --git a/src/map/duel.c b/src/map/duel.c
index 5e305244a..30277be50 100644
--- a/src/map/duel.c
+++ b/src/map/duel.c
@@ -24,7 +24,7 @@ void duel_savetime(struct map_session_data* sd) {
time(&clock);
t = localtime(&clock);
- pc_setglobalreg(sd, "PC_LAST_DUEL_TIME", t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min);
+ pc_setglobalreg(sd, script->add_str("PC_LAST_DUEL_TIME"), t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min);
}
int duel_checktime(struct map_session_data* sd) {
@@ -35,7 +35,7 @@ int duel_checktime(struct map_session_data* sd) {
time(&clock);
t = localtime(&clock);
- diff = t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min - pc_readglobalreg(sd, "PC_LAST_DUEL_TIME");
+ diff = t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min - pc_readglobalreg(sd, script->add_str("PC_LAST_DUEL_TIME") );
return !(diff >= 0 && diff < battle_config.duel_time_interval);
}
diff --git a/src/map/instance.c b/src/map/instance.c
index 924bbfd14..7c092e6cb 100644
--- a/src/map/instance.c
+++ b/src/map/instance.c
@@ -109,7 +109,8 @@ int instance_create(int owner_id, const char *name, enum instance_owner_type typ
instance->list[i].num_map = 0;
instance->list[i].owner_id = owner_id;
instance->list[i].owner_type = type;
- instance->list[i].vars = idb_alloc(DB_OPT_RELEASE_DATA);
+ instance->list[i].vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ instance->list[i].array_db = NULL;
instance->list[i].respawn.map = 0;
instance->list[i].respawn.y = 0;
instance->list[i].respawn.x = 0;
@@ -551,6 +552,8 @@ void instance_destroy(int instance_id) {
if( instance->list[instance_id].vars )
db_destroy(instance->list[instance_id].vars);
+ if( instance->list[instance_id].array_db )
+ instance->list[instance_id].array_db->destroy(instance->list[instance_id].array_db,script->array_free_db);
if( instance->list[instance_id].progress_timer != INVALID_TIMER )
timer->delete( instance->list[instance_id].progress_timer, instance->destroy_timer);
diff --git a/src/map/instance.h b/src/map/instance.h
index 4f65d7db0..ddca3e36b 100644
--- a/src/map/instance.h
+++ b/src/map/instance.h
@@ -33,8 +33,9 @@ struct instance_data {
unsigned short num_map;
unsigned short users;
- struct DBMap* vars; // Instance Variable for scripts
-
+ struct DBMap *vars; // Instance Variable for scripts
+ struct DBMap *array_db ;
+
int progress_timer;
unsigned int progress_timeout;
diff --git a/src/map/intif.c b/src/map/intif.c
index b9d4d1746..0a36fbc3d 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -265,60 +265,117 @@ int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes)
return 0;
}
-int intif_regtostr(char* str, struct global_reg *reg, int qty)
-{
- int len =0, i;
-
- for (i = 0; i < qty; i++) {
- len+= sprintf(str+len, "%s", reg[i].str)+1; //We add 1 to consider the '\0' in place.
- len+= sprintf(str+len, "%s", reg[i].value)+1;
- }
- return len;
-}
-
//Request for saving registry values.
-int intif_saveregistry(struct map_session_data *sd, int type)
-{
- struct global_reg *reg;
- int count;
- int i, p;
+int intif_saveregistry(struct map_session_data *sd) {
+ DBIterator *iter;
+ DBKey key;
+ DBData *data;
+ int plen = 0;
+ size_t len;
if (intif->CheckForCharServer())
return -1;
-
- switch (type) {
- case 3: //Character reg
- reg = sd->save_reg.global;
- count = sd->save_reg.global_num;
- sd->state.reg_dirty &= ~0x4;
- break;
- case 2: //Account reg
- reg = sd->save_reg.account;
- count = sd->save_reg.account_num;
- sd->state.reg_dirty &= ~0x2;
- break;
- case 1: //Account2 reg
- reg = sd->save_reg.account2;
- count = sd->save_reg.account2_num;
- sd->state.reg_dirty &= ~0x1;
- break;
- default: //Broken code?
- ShowError("intif_saveregistry: Invalid type %d\n", type);
- return -1;
- }
- WFIFOHEAD(inter_fd, 288 * MAX_REG_NUM+13);
- WFIFOW(inter_fd,0)=0x3004;
- WFIFOL(inter_fd,4)=sd->status.account_id;
- WFIFOL(inter_fd,8)=sd->status.char_id;
- WFIFOB(inter_fd,12)=type;
- for( p = 13, i = 0; i < count; i++ ) {
- if (reg[i].str[0] != '\0' && reg[i].value[0] != '\0') {
- p+= sprintf((char*)WFIFOP(inter_fd,p), "%s", reg[i].str)+1; //We add 1 to consider the '\0' in place.
- p+= sprintf((char*)WFIFOP(inter_fd,p), "%s", reg[i].value)+1;
+
+ WFIFOHEAD(inter_fd, 60000 + 300);
+ WFIFOW(inter_fd,0) = 0x3004;
+ /* 0x2 = length (set later) */
+ WFIFOL(inter_fd,4) = sd->status.account_id;
+ WFIFOL(inter_fd,8) = sd->status.char_id;
+ WFIFOW(inter_fd,12) = 0;/* count */
+
+ plen = 14;
+
+ iter = db_iterator(sd->var_db);
+ for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) {
+ const char *varname = NULL;
+ void *src = NULL;
+
+ if( data->type != DB_DATA_PTR ) /* its a @number */
+ continue;
+
+ varname = script->get_str(script_getvarid(key.i64));
+
+ if( varname[0] == '@' ) /* @string$ can get here, so we skip */
+ continue;
+
+ src = DB->data2ptr(data);
+
+ /* no need! */
+ if( !((struct script_reg_state*)src)->update )
+ continue;
+
+ ((struct script_reg_state*)src)->update = false;
+
+ len = strlen(varname)+1;
+
+ WFIFOB(inter_fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(inter_fd,plen), varname, len);
+ plen += len;
+
+ WFIFOL(inter_fd, plen) = script_getvaridx(key.i64);
+ plen += 4;
+
+ if( ((struct script_reg_state*)src)->type ) {
+ struct script_reg_str *p = src;
+
+ WFIFOB(inter_fd, plen) = p->value ? 2 : 3;
+ plen += 1;
+
+ if( p->value ) {
+ len = strlen(p->value)+1;
+
+ WFIFOB(inter_fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ plen += 1;
+
+ safestrncpy((char*)WFIFOP(inter_fd,plen), p->value, len);
+ plen += len;
+ } else {
+ script->reg_destroy_single(sd,key.i64,&p->flag);
+ }
+
+ } else {
+ struct script_reg_num *p = src;
+
+ WFIFOB(inter_fd, plen) = p->value ? 0 : 1;
+ plen += 1;
+
+ if( p->value ) {
+ WFIFOL(inter_fd, plen) = p->value;
+ plen += 4;
+ } else {
+ script->reg_destroy_single(sd,key.i64,&p->flag);
+ }
+
+ }
+
+ WFIFOW(inter_fd,12) += 1;
+
+ if( plen > 60000 ) {
+ WFIFOW(inter_fd, 2) = plen;
+ WFIFOSET(inter_fd, plen);
+
+ /* prepare follow up */
+ WFIFOHEAD(inter_fd, 60000 + 300);
+ WFIFOW(inter_fd,0) = 0x3004;
+ /* 0x2 = length (set later) */
+ WFIFOL(inter_fd,4) = sd->status.account_id;
+ WFIFOL(inter_fd,8) = sd->status.char_id;
+ WFIFOW(inter_fd,12) = 0;/* count */
+
+ plen = 14;
}
+
}
- WFIFOW(inter_fd,2)=p;
- WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+ dbi_destroy(iter);
+
+ /* mark & go. */
+ WFIFOW(inter_fd, 2) = plen;
+ WFIFOSET(inter_fd, plen);
+
+ sd->vars_dirty = false;
+
return 0;
}
@@ -327,10 +384,7 @@ int intif_request_registry(struct map_session_data *sd, int flag)
{
nullpo_ret(sd);
- sd->save_reg.account2_num = -1;
- sd->save_reg.account_num = -1;
- sd->save_reg.global_num = -1;
-
+ /* if char server aint online it doesn't load, shouldn't we kill the session then? */
if (intif->CheckForCharServer())
return 0;
@@ -927,54 +981,93 @@ void mapif_parse_WisToGM(int fd)
// Request player registre
void intif_parse_Registers(int fd)
{
- int j,p,len,max, flag;
+ int i, flag;
struct map_session_data *sd;
- struct global_reg *reg;
- int *qty;
int account_id = RFIFOL(fd,4), char_id = RFIFOL(fd,8);
struct auth_node *node = chrif->auth_check(account_id, char_id, ST_LOGIN);
+ char type = RFIFOB(fd, 13);
+
if (node)
sd = node->sd;
else { //Normally registries should arrive for in log-in chars.
sd = map->id2sd(account_id);
- if (sd && RFIFOB(fd,12) == 3 && sd->status.char_id != char_id)
- sd = NULL; //Character registry from another character.
}
- if (!sd) return;
-
- flag = (sd->save_reg.global_num == -1 || sd->save_reg.account_num == -1 || sd->save_reg.account2_num == -1);
-
+
+ if (!sd || sd->status.char_id != char_id) {
+ return; //Character registry from another character.
+ }
+
+ flag = ( sd->vars_received&PRL_ACCG && sd->vars_received&PRL_ACCL && sd->vars_received&PRL_CHAR ) ? 0 : 1;
+
switch (RFIFOB(fd,12)) {
case 3: //Character Registry
- reg = sd->save_reg.global;
- qty = &sd->save_reg.global_num;
- max = GLOBAL_REG_NUM;
- break;
+ sd->vars_received |= PRL_CHAR;
+ break;
case 2: //Account Registry
- reg = sd->save_reg.account;
- qty = &sd->save_reg.account_num;
- max = ACCOUNT_REG_NUM;
- break;
+ sd->vars_received |= PRL_ACCL;
+ break;
case 1: //Account2 Registry
- reg = sd->save_reg.account2;
- qty = &sd->save_reg.account2_num;
- max = ACCOUNT_REG2_NUM;
- break;
+ sd->vars_received |= PRL_ACCG;
+ break;
+ case 0:
+ break;
default:
ShowError("intif_parse_Registers: Unrecognized type %d\n",RFIFOB(fd,12));
return;
}
- for(j=0,p=13;j<max && p<RFIFOW(fd,2);j++){
- sscanf((char*)RFIFOP(fd,p), "%31c%n", reg[j].str,&len);
- reg[j].str[len]='\0';
- p += len+1; //+1 to skip the '\0' between strings.
- sscanf((char*)RFIFOP(fd,p), "%255c%n", reg[j].value,&len);
- reg[j].value[len]='\0';
- p += len+1;
+ /* have it not complain about insertion of vars before loading, and not set those vars as new or modified */
+ pc->reg_load = true;
+
+ if( RFIFOW(fd, 14) ) {
+ char key[32], sval[254];
+ unsigned int index;
+ int max = RFIFOW(fd, 14), cursor = 16, ival;
+
+ /**
+ * Vessel!char_reg_num_db
+ *
+ * str type
+ * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) }
+ **/
+ if( type ) {
+ for(i = 0; i < max; i++) {
+ safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+
+ index = RFIFOL(fd, cursor);
+ cursor += 4;
+
+ safestrncpy(sval, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+
+ script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (void*)sval, NULL);
+ }
+ /**
+ * Vessel!
+ *
+ * int type
+ * { keyLength(B), key(<keyLength>), index(L), value(L) }
+ **/
+ } else {
+ for(i = 0; i < max; i++) {
+ safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor));
+ cursor += RFIFOB(fd, cursor) + 1;
+
+ index = RFIFOL(fd, cursor);
+ cursor += 4;
+
+ ival = RFIFOL(fd, cursor);
+ cursor += 4;
+
+ script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (void*)__64BPTRSIZE(ival), NULL);
+ }
+ }
}
- *qty = j;
-
- if (flag && sd->save_reg.global_num > -1 && sd->save_reg.account_num > -1 && sd->save_reg.account2_num > -1)
+
+ /* flag it back */
+ pc->reg_load = false;
+
+ if (flag && sd->vars_received&PRL_ACCG && sd->vars_received&PRL_ACCL && sd->vars_received&PRL_CHAR)
pc->reg_received(sd); //Received all registry values, execute init scripts and what-not. [Skotlex]
}
diff --git a/src/map/intif.h b/src/map/intif.h
index bd3908ce7..f0bb5c16e 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -45,7 +45,7 @@ struct intif_interface {
int (*main_message) (struct map_session_data* sd, const char* message);
int (*wis_message) (struct map_session_data *sd,char *nick,char *mes,size_t mes_len);
int (*wis_message_to_gm) (char *Wisp_name, int permission, char *mes);
- int (*saveregistry) (struct map_session_data *sd, int type);
+ int (*saveregistry) (struct map_session_data *sd);
int (*request_registry) (struct map_session_data *sd, int flag);
int (*request_guild_storage) (int account_id, int guild_id);
int (*send_guild_storage) (int account_id, struct guild_storage *gstor);
diff --git a/src/map/mapreg.h b/src/map/mapreg.h
index c8f229cef..157e634cc 100644
--- a/src/map/mapreg.h
+++ b/src/map/mapreg.h
@@ -9,7 +9,7 @@
#include "../common/db.h"
struct mapreg_save {
- int uid;
+ int64 uid;
union {
int i;
char *str;
@@ -19,19 +19,27 @@ struct mapreg_save {
struct mapreg_interface {
DBMap *db; // int var_id -> int value
+ /* TODO duck str_db, use same */
DBMap *str_db; // int var_id -> char* value
+ /* */
+ DBMap *array_db;
+ /* */
+ bool skip_insert;
+ /* */
struct eri *ers; //[Ind/Hercules]
+ /* */
char table[32];
+ /* */
bool i_dirty;
bool str_dirty;
/* */
void (*init) (void);
void (*final) (void);
/* */
- int (*readreg) (int uid);
- char* (*readregstr) (int uid);
- bool (*setreg) (int uid, int val);
- bool (*setregstr) (int uid, const char *str);
+ int (*readreg) (int64 uid);
+ char* (*readregstr) (int64 uid);
+ bool (*setreg) (int64 uid, int val);
+ bool (*setregstr) (int64 uid, const char *str);
void (*load) (void);
void (*save) (void);
int (*save_timer) (int tid, int64 tick, int id, intptr_t data);
diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c
index 6a13ef2a0..6df614aac 100644
--- a/src/map/mapreg_sql.c
+++ b/src/map/mapreg_sql.c
@@ -21,51 +21,56 @@ struct mapreg_interface mapreg_s;
#define MAPREG_AUTOSAVE_INTERVAL (300*1000)
/// Looks up the value of an integer variable using its uid.
-int mapreg_readreg(int uid) {
- struct mapreg_save *m = idb_get(mapreg->db, uid);
+int mapreg_readreg(int64 uid) {
+ struct mapreg_save *m = i64db_get(mapreg->db, uid);
return m?m->u.i:0;
}
/// Looks up the value of a string variable using its uid.
-char* mapreg_readregstr(int uid) {
- struct mapreg_save *m = idb_get(mapreg->str_db, uid);
+char* mapreg_readregstr(int64 uid) {
+ struct mapreg_save *m = i64db_get(mapreg->str_db, uid);
return m?m->u.str:NULL;
}
/// Modifies the value of an integer variable.
-bool mapreg_setreg(int uid, int val) {
+bool mapreg_setreg(int64 uid, int val) {
struct mapreg_save *m;
- int num = (uid & 0x00ffffff);
- int i = (uid & 0xff000000) >> 24;
+ int num = script_getvarid(uid);
+ unsigned int i = script_getvaridx(uid);
const char* name = script->get_str(num);
if( val != 0 ) {
- if( (m = idb_get(mapreg->db,uid)) ) {
+ if( (m = i64db_get(mapreg->db,uid)) ) {
m->u.i = val;
if(name[1] != '@') {
m->save = true;
mapreg->i_dirty = true;
}
} else {
+ if( i )
+ script->array_update(&mapreg->array_db,uid,false);
+
m = ers_alloc(mapreg->ers, struct mapreg_save);
m->u.i = val;
m->uid = uid;
m->save = false;
- if(name[1] != '@') {// write new variable to database
+ if(name[1] != '@' && !mapreg->skip_insert) {// write new variable to database
char tmp_str[32*2+1];
SQL->EscapeStringLen(map->mysql_handle, tmp_str, name, strnlen(name, 32));
if( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%d')", mapreg->table, tmp_str, i, val) )
Sql_ShowDebug(map->mysql_handle);
}
- idb_put(mapreg->db, uid, m);
+ i64db_put(mapreg->db, uid, m);
}
} else { // val == 0
- if( (m = idb_get(mapreg->db,uid)) ) {
+ if( i )
+ script->array_update(&mapreg->array_db,uid,true);
+ if( (m = i64db_get(mapreg->db,uid)) ) {
ers_free(mapreg->ers, m);
}
- idb_remove(mapreg->db,uid);
+ i64db_remove(mapreg->db,uid);
if( name[1] != '@' ) {// Remove from database because it is unused.
if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg->table, name, i) )
@@ -77,25 +82,27 @@ bool mapreg_setreg(int uid, int val) {
}
/// Modifies the value of a string variable.
-bool mapreg_setregstr(int uid, const char* str) {
+bool mapreg_setregstr(int64 uid, const char* str) {
struct mapreg_save *m;
- int num = (uid & 0x00ffffff);
- int i = (uid & 0xff000000) >> 24;
+ int num = script_getvarid(uid);
+ unsigned int i = script_getvaridx(uid);
const char* name = script->get_str(num);
if( str == NULL || *str == 0 ) {
+ if( i )
+ script->array_update(&mapreg->array_db,uid,true);
if(name[1] != '@') {
if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg->table, name, i) )
Sql_ShowDebug(map->mysql_handle);
}
- if( (m = idb_get(mapreg->str_db,uid)) ) {
+ if( (m = i64db_get(mapreg->str_db,uid)) ) {
if( m->u.str != NULL )
aFree(m->u.str);
ers_free(mapreg->ers, m);
}
- idb_remove(mapreg->str_db,uid);
+ i64db_remove(mapreg->str_db,uid);
} else {
- if( (m = idb_get(mapreg->str_db,uid)) ) {
+ if( (m = i64db_get(mapreg->str_db,uid)) ) {
if( m->u.str != NULL )
aFree(m->u.str);
m->u.str = aStrdup(str);
@@ -104,13 +111,16 @@ bool mapreg_setregstr(int uid, const char* str) {
m->save = true;
}
} else {
+ if( i )
+ script->array_update(&mapreg->array_db,uid,false);
+
m = ers_alloc(mapreg->ers, struct mapreg_save);
m->uid = uid;
m->u.str = aStrdup(str);
m->save = false;
- if(name[1] != '@') { //put returned null, so we must insert.
+ if(name[1] != '@' && !mapreg->skip_insert) { //put returned null, so we must insert.
char tmp_str[32*2+1];
char tmp_str2[255*2+1];
SQL->EscapeStringLen(map->mysql_handle, tmp_str, name, strnlen(name, 32));
@@ -118,7 +128,7 @@ bool mapreg_setregstr(int uid, const char* str) {
if( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%s')", mapreg->table, tmp_str, i, tmp_str2) )
Sql_ShowDebug(map->mysql_handle);
}
- idb_put(mapreg->str_db, uid, m);
+ i64db_put(mapreg->str_db, uid, m);
}
}
@@ -147,41 +157,36 @@ void script_load_mapreg(void) {
return;
}
+ mapreg->skip_insert = true;
+
SQL->StmtBindColumn(stmt, 0, SQLDT_STRING, &varname[0], sizeof(varname), &length, NULL);
SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &index, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 2, SQLDT_STRING, &value[0], sizeof(value), NULL, NULL);
-
+
while ( SQL_SUCCESS == SQL->StmtNextRow(stmt) ) {
- struct mapreg_save *m = NULL;
int s = script->add_str(varname);
int i = index;
+
if( varname[length-1] == '$' ) {
- if( idb_exists(mapreg->str_db, (i<<24)|s) ) {
+ if( i64db_exists(mapreg->str_db, reference_uid(s, i)) ) {
ShowWarning("load_mapreg: duplicate! '%s' => '%s' skipping...\n",varname,value);
continue;
}
+ script->set_reg(NULL,NULL,reference_uid(s, i), varname, (void*)value, NULL);
} else {
- if( idb_exists(mapreg->db, (i<<24)|s) ) {
+ if( i64db_exists(mapreg->db, reference_uid(s, i)) ) {
ShowWarning("load_mapreg: duplicate! '%s' => '%s' skipping...\n",varname,value);
continue;
}
- }
-
- m = ers_alloc(mapreg->ers, struct mapreg_save);
- m->uid = (i<<24)|s;
- m->save = false;
- if( varname[length-1] == '$' ) {
- m->u.str = aStrdup(value);
- idb_put(mapreg->str_db, m->uid, m);
- } else {
- m->u.i = atoi(value);
- idb_put(mapreg->db, m->uid, m);
+ script->set_reg(NULL,NULL,reference_uid(s, i), varname, (void*)__64BPTRSIZE(atoi(value)), NULL);
}
}
SQL->StmtFree(stmt);
+ mapreg->skip_insert = false;
+
mapreg->i_dirty = false;
mapreg->str_dirty = false;
}
@@ -195,8 +200,8 @@ void script_save_mapreg(void) {
iter = db_iterator(mapreg->db);
for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) {
if( m->save ) {
- int num = (m->uid & 0x00ffffff);
- int i = (m->uid & 0xff000000) >> 24;
+ int num = script_getvarid(m->uid);
+ int i = script_getvaridx(m->uid);
const char* name = script->get_str(num);
if( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE `%s` SET `value`='%d' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg->table, m->u.i, name, i) )
@@ -212,8 +217,8 @@ void script_save_mapreg(void) {
iter = db_iterator(mapreg->str_db);
for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) {
if( m->save ) {
- int num = (m->uid & 0x00ffffff);
- int i = (m->uid & 0xff000000) >> 24;
+ int num = script_getvarid(m->uid);
+ int i = script_getvaridx(m->uid);
const char* name = script->get_str(num);
char tmp_str2[2*255+1];
@@ -257,7 +262,10 @@ void mapreg_reload(void) {
db_clear(mapreg->db);
db_clear(mapreg->str_db);
-
+
+ if( mapreg->array_db )
+ mapreg->array_db->destroy(mapreg->array_db,script->array_free_db);
+
mapreg->load();
}
@@ -286,11 +294,14 @@ void mapreg_final(void) {
db_destroy(mapreg->str_db);
ers_destroy(mapreg->ers);
+
+ if( mapreg->array_db )
+ mapreg->array_db->destroy(mapreg->array_db,script->array_free_db);
}
void mapreg_init(void) {
- mapreg->db = idb_alloc(DB_OPT_BASE);
- mapreg->str_db = idb_alloc(DB_OPT_BASE);
+ mapreg->db = i64db_alloc(DB_OPT_BASE);
+ mapreg->str_db = i64db_alloc(DB_OPT_BASE);
mapreg->ers = ers_new(sizeof(struct mapreg_save), "mapreg_sql.c::mapreg_ers", ERS_OPT_CLEAN);
mapreg->load();
@@ -314,12 +325,16 @@ void mapreg_defaults(void) {
mapreg->db = NULL;
mapreg->str_db = NULL;
mapreg->ers = NULL;
+ mapreg->skip_insert = false;
safestrncpy(mapreg->table, "mapreg", sizeof(mapreg->table));
mapreg->i_dirty = false;
mapreg->str_dirty = false;
/* */
+ mapreg->array_db = NULL;
+
+ /* */
mapreg->init = mapreg_init;
mapreg->final = mapreg_final;
diff --git a/src/map/mob.c b/src/map/mob.c
index d919e7478..6a8aa5f03 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -2552,11 +2552,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
if( ++sd->mission_count >= 100 && (temp = mob->get_random_id(0, 0xE, sd->status.base_level)) ) {
pc->addfame(sd, 1);
sd->mission_mobid = temp;
- pc_setglobalreg(sd,"TK_MISSION_ID", temp);
+ pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), temp);
sd->mission_count = 0;
clif->mission_info(sd, temp, 0);
}
- pc_setglobalreg(sd,"TK_MISSION_COUNT", sd->mission_count);
+ pc_setglobalreg(sd,script->add_str("TK_MISSION_COUNT"), sd->mission_count);
}
if( sd->status.party_id )
diff --git a/src/map/pc.c b/src/map/pc.c
index 9e819bcac..b090b7b17 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -968,7 +968,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
uint32 ip = session[sd->fd]->client_addr;
sd->login_id2 = login_id2;
-
+
if (pc->set_group(sd, group_id) != 0) {
ShowWarning("pc_authok: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
st->name, sd->status.account_id, group_id);
@@ -1108,6 +1108,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->avail_quests = 0;
sd->save_quest = false;
+ sd->var_db = i64db_alloc(DB_OPT_BASE);
+ sd->vars_dirty = false;
+ sd->vars_ok = false;
+ sd->vars_received = 0x0;
+
//warp player
if ((i=pc->setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) {
ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i);
@@ -1214,7 +1219,7 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl)
return 0; //Wrong size
}
sd->hate_mob[pos] = class_;
- pc_setglobalreg(sd,pc->sg_info[pos].hate_var,class_+1);
+ pc_setglobalreg(sd,script->add_str(pc->sg_info[pos].hate_var),class_+1);
clif->hate_info(sd, pos, class_, 1);
return 1;
}
@@ -1226,55 +1231,58 @@ int pc_reg_received(struct map_session_data *sd)
{
int i,j, idx = 0;
- sd->change_level_2nd = pc_readglobalreg(sd,"jobchange_level");
- sd->change_level_3rd = pc_readglobalreg(sd,"jobchange_level_3rd");
- sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER");
+ sd->vars_ok = true;
+
+ sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level"));
+ sd->change_level_3rd = pc_readglobalreg(sd,script->add_str("jobchange_level_3rd"));
+ sd->die_counter = pc_readglobalreg(sd,script->add_str("PC_DIE_COUNTER"));
// Cash shop
- sd->cashPoints = pc_readaccountreg(sd,"#CASHPOINTS");
- sd->kafraPoints = pc_readaccountreg(sd,"#KAFRAPOINTS");
+ sd->cashPoints = pc_readaccountreg(sd,script->add_str("#CASHPOINTS"));
+ sd->kafraPoints = pc_readaccountreg(sd,script->add_str("#KAFRAPOINTS"));
// Cooking Exp
- sd->cook_mastery = pc_readglobalreg(sd,"COOK_MASTERY");
+ sd->cook_mastery = pc_readglobalreg(sd,script->add_str("COOK_MASTERY"));
if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) {
// Better check for class rather than skill to prevent "skill resets" from unsetting this
- sd->mission_mobid = pc_readglobalreg(sd,"TK_MISSION_ID");
- sd->mission_count = pc_readglobalreg(sd,"TK_MISSION_COUNT");
+ sd->mission_mobid = pc_readglobalreg(sd,script->add_str("TK_MISSION_ID"));
+ sd->mission_count = pc_readglobalreg(sd,script->add_str("TK_MISSION_COUNT"));
}
//SG map and mob read [Komurka]
for(i=0;i<MAX_PC_FEELHATE;i++) { //for now - someone need to make reading from txt/sql
- if ((j = pc_readglobalreg(sd,pc->sg_info[i].feel_var))!=0) {
+ if ((j = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].feel_var)))!=0) {
sd->feel_map[i].index = j;
sd->feel_map[i].m = map->mapindex2mapid(j);
} else {
sd->feel_map[i].index = 0;
sd->feel_map[i].m = -1;
}
- sd->hate_mob[i] = pc_readglobalreg(sd,pc->sg_info[i].hate_var)-1;
+ sd->hate_mob[i] = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].hate_var))-1;
}
if ((i = pc->checkskill(sd,RG_PLAGIARISM)) > 0) {
- sd->cloneskill_id = pc_readglobalreg(sd,"CLONE_SKILL");
+ sd->cloneskill_id = pc_readglobalreg(sd,script->add_str("CLONE_SKILL"));
if (sd->cloneskill_id > 0 && (idx = skill->get_index(sd->cloneskill_id))) {
sd->status.skill[idx].id = sd->cloneskill_id;
- sd->status.skill[idx].lv = pc_readglobalreg(sd,"CLONE_SKILL_LV");
+ sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("CLONE_SKILL_LV"));
if (sd->status.skill[idx].lv > i)
sd->status.skill[idx].lv = i;
sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED;
}
}
if ((i = pc->checkskill(sd,SC_REPRODUCE)) > 0) {
- sd->reproduceskill_id = pc_readglobalreg(sd,"REPRODUCE_SKILL");
+ sd->reproduceskill_id = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL"));
if( sd->reproduceskill_id > 0 && (idx = skill->get_index(sd->reproduceskill_id))) {
sd->status.skill[idx].id = sd->reproduceskill_id;
- sd->status.skill[idx].lv = pc_readglobalreg(sd,"REPRODUCE_SKILL_LV");
+ sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL_LV"));
if( i < sd->status.skill[idx].lv)
sd->status.skill[idx].lv = i;
sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED;
}
}
+
//Weird... maybe registries were reloaded?
if (sd->state.active)
return 0;
@@ -1652,7 +1660,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd)
}
- pc_setglobalreg (sd, "jobchange_level", sd->change_level_2nd);
+ pc_setglobalreg (sd, script->add_str("jobchange_level"), sd->change_level_2nd);
}
if (skill_point < novice_skills + (sd->change_level_2nd - 1)) {
@@ -1665,7 +1673,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd)
- (sd->status.job_level - 1)
- (sd->change_level_2nd - 1)
- novice_skills;
- pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd);
+ pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd);
}
if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) {
@@ -3777,8 +3785,8 @@ int pc_paycash(struct map_session_data *sd, int price, int points)
return -1;
}
- pc_setaccountreg(sd, "#CASHPOINTS", sd->cashPoints-cash);
- pc_setaccountreg(sd, "#KAFRAPOINTS", sd->kafraPoints-points);
+ pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints-cash);
+ pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints-points);
if( battle_config.cashshop_show_points )
{
@@ -3804,7 +3812,7 @@ int pc_getcash(struct map_session_data *sd, int cash, int points)
cash = MAX_ZENY-sd->cashPoints;
}
- pc_setaccountreg(sd, "#CASHPOINTS", sd->cashPoints+cash);
+ pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints+cash);
if( battle_config.cashshop_show_points )
{
@@ -3827,7 +3835,7 @@ int pc_getcash(struct map_session_data *sd, int cash, int points)
points = MAX_ZENY-sd->kafraPoints;
}
- pc_setaccountreg(sd, "#KAFRAPOINTS", sd->kafraPoints+points);
+ pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints+points);
if( battle_config.cashshop_show_points )
{
@@ -6505,7 +6513,7 @@ int pc_resetstate(struct map_session_data* sd)
if( sd->mission_mobid ) { //bugreport:2200
sd->mission_mobid = 0;
sd->mission_count = 0;
- pc_setglobalreg(sd,"TK_MISSION_ID", 0);
+ pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), 0);
}
status_calc_pc(sd,SCO_NONE);
@@ -6637,7 +6645,7 @@ int pc_resetfeel(struct map_session_data* sd)
{
sd->feel_map[i].m = -1;
sd->feel_map[i].index = 0;
- pc_setglobalreg(sd,pc->sg_info[i].feel_var,0);
+ pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),0);
}
return 0;
@@ -6651,7 +6659,7 @@ int pc_resethate(struct map_session_data* sd)
for (i=0; i<3; i++)
{
sd->hate_mob[i] = -1;
- pc_setglobalreg(sd,pc->sg_info[i].hate_var,0);
+ pc_setglobalreg(sd,script->add_str(pc->sg_info[i].hate_var),0);
}
return 0;
}
@@ -6806,7 +6814,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) {
if (sd->npc_id && sd->st && sd->st->state != RUN)
npc->event_dequeue(sd);
- pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1);
+ pc_setglobalreg(sd,script->add_str("PC_DIE_COUNTER"),sd->die_counter+1);
pc->setparam(sd, SP_KILLERRID, src?src->id:0);
if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */
@@ -7608,12 +7616,12 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
// changing from 1st to 2nd job
if ((b_class&JOBL_2) && !(sd->class_&JOBL_2) && (b_class&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) {
sd->change_level_2nd = sd->status.job_level;
- pc_setglobalreg (sd, "jobchange_level", sd->change_level_2nd);
+ pc_setglobalreg (sd, script->add_str("jobchange_level"), sd->change_level_2nd);
}
// changing from 2nd to 3rd job
else if((b_class&JOBL_THIRD) && !(sd->class_&JOBL_THIRD)) {
sd->change_level_3rd = sd->status.job_level;
- pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd);
+ pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd);
}
if(sd->cloneskill_id) {
@@ -7625,8 +7633,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
clif->deleteskill(sd,sd->cloneskill_id);
}
sd->cloneskill_id = 0;
- pc_setglobalreg(sd, "CLONE_SKILL", 0);
- pc_setglobalreg(sd, "CLONE_SKILL_LV", 0);
+ pc_setglobalreg(sd, script->add_str("CLONE_SKILL"), 0);
+ pc_setglobalreg(sd, script->add_str("CLONE_SKILL_LV"), 0);
}
if(sd->reproduceskill_id) {
@@ -7638,8 +7646,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
clif->deleteskill(sd,sd->reproduceskill_id);
}
sd->reproduceskill_id = 0;
- pc_setglobalreg(sd, "REPRODUCE_SKILL",0);
- pc_setglobalreg(sd, "REPRODUCE_SKILL_LV",0);
+ pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL"),0);
+ pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL_LV"),0);
}
if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree.
@@ -8044,341 +8052,245 @@ int pc_candrop(struct map_session_data *sd, struct item *item)
return 0;
return (itemdb_isdropable(item, pc_get_group_level(sd)));
}
-
-/*==========================================
- * Read ram register for player sd
- * get val (int) from reg for player sd
- *------------------------------------------*/
-int pc_readreg(struct map_session_data* sd, int reg)
-{
- int i;
-
- nullpo_ret(sd);
-
- ARR_FIND( 0, sd->reg_num, i, sd->reg[i].index == reg );
- return ( i < sd->reg_num ) ? sd->reg[i].data : 0;
+/**
+ * For '@type' variables (temporary numeric char reg)
+ **/
+int pc_readreg(struct map_session_data* sd, int64 reg) {
+ return i64db_iget(sd->var_db, reg);
}
-/*==========================================
- * Set ram register for player sd
- * memo val(int) at reg for player sd
- *------------------------------------------*/
-int pc_setreg(struct map_session_data* sd, int reg, int val)
-{
- int i;
-
- nullpo_ret(sd);
-
- ARR_FIND( 0, sd->reg_num, i, sd->reg[i].index == reg );
- if( i < sd->reg_num )
- {// overwrite existing entry
- sd->reg[i].data = val;
- return 1;
- }
-
- ARR_FIND( 0, sd->reg_num, i, sd->reg[i].data == 0 );
- if( i == sd->reg_num )
- {// nothing free, increase size
- sd->reg_num++;
- RECREATE(sd->reg, struct script_reg, sd->reg_num);
+/**
+ * For '@type' variables (temporary numeric char reg)
+ **/
+void pc_setreg(struct map_session_data* sd, int64 reg, int val) {
+ unsigned int index = script_getvaridx(reg);
+
+ if( val ) {
+ i64db_iput(sd->var_db, reg, val);
+ if( index )
+ script->array_update(&sd->array_db,reg,false);
+ } else {
+ i64db_remove(sd->var_db, reg);
+ if( index )
+ script->array_update(&sd->array_db,reg,true);
}
- sd->reg[i].index = reg;
- sd->reg[i].data = val;
-
- return 1;
}
-/*==========================================
- * Read ram register for player sd
- * get val (str) from reg for player sd
- *------------------------------------------*/
-char* pc_readregstr(struct map_session_data* sd, int reg)
-{
- int i;
-
- nullpo_ret(sd);
+/**
+ * For '@type$' variables (temporary string char reg)
+ **/
+char* pc_readregstr(struct map_session_data* sd, int64 reg) {
+ struct script_reg_str *p = NULL;
- ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].index == reg );
- return ( i < sd->regstr_num ) ? sd->regstr[i].data : NULL;
+ p = i64db_get(sd->var_db, reg);
+
+ return p ? p->value : NULL;
}
-/*==========================================
- * Set ram register for player sd
- * memo val(str) at reg for player sd
- *------------------------------------------*/
-int pc_setregstr(struct map_session_data* sd, int reg, const char* str)
-{
- int i;
-
- nullpo_ret(sd);
+/**
+ * For '@type$' variables (temporary string char reg)
+ **/
+void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) {
+ struct script_reg_str *p = NULL;
+ unsigned int index = script_getvaridx(reg);
+ DBData prev;
- ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].index == reg );
- if( i < sd->regstr_num )
- {// found entry, update
- if( str == NULL || *str == '\0' )
- {// empty string
- if( sd->regstr[i].data != NULL )
- aFree(sd->regstr[i].data);
- sd->regstr[i].data = NULL;
- }
- else if( sd->regstr[i].data )
- {// recreate
- size_t len = strlen(str)+1;
- RECREATE(sd->regstr[i].data, char, len);
- memcpy(sd->regstr[i].data, str, len*sizeof(char));
+ if( str[0] ) {
+ p = ers_alloc(pc->str_reg_ers, struct script_reg_str);
+
+ p->value = aStrdup(str);
+
+ if( sd->var_db->put(sd->var_db,DB->i642key(reg),DB->ptr2data(p),&prev) ) {
+ p = DB->data2ptr(&prev);
+ if( p->value )
+ aFree(p->value);
+ ers_free(pc->str_reg_ers, p);
+ } else {
+ if( index )
+ script->array_update(&sd->array_db,reg,false);
}
- else
- {// create
- sd->regstr[i].data = aStrdup(str);
+ } else {
+ if( sd->var_db->remove(sd->var_db,DB->i642key(reg),&prev) ) {
+ p = DB->data2ptr(&prev);
+ if( p->value )
+ aFree(p->value);
+ ers_free(pc->str_reg_ers, p);
+ if( index )
+ script->array_update(&sd->array_db,reg,true);
}
- return 1;
- }
-
- if( str == NULL || *str == '\0' )
- return 1;// nothing to add, empty string
-
- ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].data == NULL );
- if( i == sd->regstr_num )
- {// nothing free, increase size
- sd->regstr_num++;
- RECREATE(sd->regstr, struct script_regstr, sd->regstr_num);
}
- sd->regstr[i].index = reg;
- sd->regstr[i].data = aStrdup(str);
-
- return 1;
}
-
-int pc_readregistry(struct map_session_data *sd,const char *reg,int type)
-{
- struct global_reg *sd_reg;
- int i,max;
-
- nullpo_ret(sd);
- switch (type) {
- case 3: //Char reg
- sd_reg = sd->save_reg.global;
- max = sd->save_reg.global_num;
- break;
- case 2: //Account reg
- sd_reg = sd->save_reg.account;
- max = sd->save_reg.account_num;
- break;
- case 1: //Account2 reg
- sd_reg = sd->save_reg.account2;
- max = sd->save_reg.account2_num;
- break;
- default:
- return 0;
- }
- if (max == -1) {
- ShowError("pc_readregistry: Trying to read reg value %s (type %d) before it's been loaded!\n", reg, type);
+/**
+ * Serves the following variable types:
+ * - 'type' (permanent nuneric char reg)
+ * - '#type' (permanent numeric account reg)
+ * - '##type' (permanent numeric account reg2)
+ **/
+int pc_readregistry(struct map_session_data *sd, int64 reg) {
+ struct script_reg_num *p = NULL;
+
+ if (!sd->vars_ok) {
+ ShowError("pc_readregistry: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg)));
//This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again.
- intif->request_registry(sd,type==3?4:type);
+ //intif->request_registry(sd,type==3?4:type);
+ set_eof(sd->fd);
return 0;
}
+
+ p = i64db_get(sd->var_db, reg);
- ARR_FIND( 0, max, i, strcmp(sd_reg[i].str,reg) == 0 );
- return ( i < max ) ? atoi(sd_reg[i].value) : 0;
+ return p ? p->value : 0;
}
-
-char* pc_readregistry_str(struct map_session_data *sd,const char *reg,int type)
-{
- struct global_reg *sd_reg;
- int i,max;
-
- nullpo_ret(sd);
- switch (type) {
- case 3: //Char reg
- sd_reg = sd->save_reg.global;
- max = sd->save_reg.global_num;
- break;
- case 2: //Account reg
- sd_reg = sd->save_reg.account;
- max = sd->save_reg.account_num;
- break;
- case 1: //Account2 reg
- sd_reg = sd->save_reg.account2;
- max = sd->save_reg.account2_num;
- break;
- default:
- return NULL;
- }
- if (max == -1) {
- ShowError("pc_readregistry: Trying to read reg value %s (type %d) before it's been loaded!\n", reg, type);
+/**
+ * Serves the following variable types:
+ * - 'type$' (permanent str char reg)
+ * - '#type$' (permanent str account reg)
+ * - '##type$' (permanent str account reg2)
+ **/
+char* pc_readregistry_str(struct map_session_data *sd, int64 reg) {
+ struct script_reg_str *p = NULL;
+
+ if (!sd->vars_ok) {
+ ShowError("pc_readregistry_str: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg)));
//This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again.
- intif->request_registry(sd,type==3?4:type);
+ //intif->request_registry(sd,type==3?4:type);
+ set_eof(sd->fd);
return NULL;
}
- ARR_FIND( 0, max, i, strcmp(sd_reg[i].str,reg) == 0 );
- return ( i < max ) ? sd_reg[i].value : NULL;
+ p = i64db_get(sd->var_db, reg);
+
+ return p ? p->value : NULL;
}
+/**
+ * Serves the following variable types:
+ * - 'type' (permanent nuneric char reg)
+ * - '#type' (permanent numeric account reg)
+ * - '##type' (permanent numeric account reg2)
+ **/
+int pc_setregistry(struct map_session_data *sd, int64 reg, int val) {
+ struct script_reg_num *p = NULL;
+ int i;
+ const char *regname = script->get_str( script_getvarid(reg) );
+ unsigned int index = script_getvaridx(reg);
-int pc_setregistry(struct map_session_data *sd,const char *reg,int val,int type)
-{
- struct global_reg *sd_reg;
- int i,*max, regmax;
-
- nullpo_ret(sd);
-
- switch( type )
- {
- case 3: //Char reg
- if( !strcmp(reg,"PC_DIE_COUNTER") && sd->die_counter != val )
- {
- i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE);
- sd->die_counter = val;
- if( i )
- status_calc_pc(sd,SCO_NONE); // Lost the bonus.
- }
- else if( !strcmp(reg,"COOK_MASTERY") && sd->cook_mastery != val )
- {
- val = cap_value(val, 0, 1999);
- sd->cook_mastery = val;
- }
- sd_reg = sd->save_reg.global;
- max = &sd->save_reg.global_num;
- regmax = GLOBAL_REG_NUM;
- break;
- case 2: //Account reg
- if( !strcmp(reg,"#CASHPOINTS") && sd->cashPoints != val )
- {
- val = cap_value(val, 0, MAX_ZENY);
- sd->cashPoints = val;
- }
- else if( !strcmp(reg,"#KAFRAPOINTS") && sd->kafraPoints != val )
- {
- val = cap_value(val, 0, MAX_ZENY);
- sd->kafraPoints = val;
- }
- sd_reg = sd->save_reg.account;
- max = &sd->save_reg.account_num;
- regmax = ACCOUNT_REG_NUM;
- break;
- case 1: //Account2 reg
- sd_reg = sd->save_reg.account2;
- max = &sd->save_reg.account2_num;
- regmax = ACCOUNT_REG2_NUM;
- break;
- default:
- return 0;
+ /* SAAD! those things should be stored elsewhere e.g. char ones in char table, the cash ones in account_data table! */
+ switch( regname[0] ) {
+ default: //Char reg
+ if( !strcmp(regname,"PC_DIE_COUNTER") && sd->die_counter != val ) {
+ i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE);
+ sd->die_counter = val;
+ if( i )
+ status_calc_pc(sd,SCO_NONE); // Lost the bonus.
+ } else if( !strcmp(regname,"COOK_MASTERY") && sd->cook_mastery != val ) {
+ val = cap_value(val, 0, 1999);
+ sd->cook_mastery = val;
+ }
+ break;
+ case '#':
+ if( !strcmp(regname,"#CASHPOINTS") && sd->cashPoints != val ) {
+ val = cap_value(val, 0, MAX_ZENY);
+ sd->cashPoints = val;
+ } else if( !strcmp(regname,"#KAFRAPOINTS") && sd->kafraPoints != val ) {
+ val = cap_value(val, 0, MAX_ZENY);
+ sd->kafraPoints = val;
+ }
+ break;
}
- if (*max == -1) {
- ShowError("pc_setregistry : refusing to set %s (type %d) until vars are received.\n", reg, type);
- return 1;
+
+ if ( !pc->reg_load && !sd->vars_ok ) {
+ ShowError("pc_setregistry : refusing to set %s until vars are received.\n", regname);
+ return 0;
}
-
- // delete reg
- if (val == 0) {
- ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 );
- if( i < *max )
- {
- if (i != *max - 1)
- memcpy(&sd_reg[i], &sd_reg[*max - 1], sizeof(struct global_reg));
- memset(&sd_reg[*max - 1], 0, sizeof(struct global_reg));
- (*max)--;
- sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved"
+
+ if( (p = i64db_get(sd->var_db, reg) ) ) {
+ if( val ) {
+ if( !p->value && index ) /* its a entry that was deleted, so we reset array */
+ script->array_update(&sd->array_db,reg,false);
+ p->value = val;
+ } else {
+ p->value = 0;
+ if( index )
+ script->array_update(&sd->array_db,reg,true);
+ }
+ if( !pc->reg_load )
+ p->flag.update = 1;/* either way, it will require either delete or replace */
+ } else if( val ) {
+ DBData prev;
+
+ if( index )
+ script->array_update(&sd->array_db,reg,false);
+
+ p = ers_alloc(pc->num_reg_ers, struct script_reg_num);
+
+ p->value = val;
+ if( !pc->reg_load )
+ p->flag.update = 1;
+
+ if( sd->var_db->put(sd->var_db,DB->i642key(reg),DB->ptr2data(p),&prev) ) {
+ p = DB->data2ptr(&prev);
+ ers_free(pc->num_reg_ers, p);
}
- return 1;
- }
- // change value if found
- ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 );
- if( i < *max )
- {
- safesnprintf(sd_reg[i].value, sizeof(sd_reg[i].value), "%d", val);
- sd->state.reg_dirty |= 1<<(type-1);
- return 1;
- }
-
- // add value if not found
- if (i < regmax) {
- memset(&sd_reg[i], 0, sizeof(struct global_reg));
- safestrncpy(sd_reg[i].str, reg, sizeof(sd_reg[i].str));
- safesnprintf(sd_reg[i].value, sizeof(sd_reg[i].value), "%d", val);
- (*max)++;
- sd->state.reg_dirty |= 1<<(type-1);
- return 1;
}
+
+ if( !pc->reg_load && p )
+ sd->vars_dirty = true;
- ShowError("pc_setregistry : couldn't set %s, limit of registries reached (%d)\n", reg, regmax);
-
- return 0;
+ return 1;
}
+/**
+ * Serves the following variable types:
+ * - 'type$' (permanent str char reg)
+ * - '#type$' (permanent str account reg)
+ * - '##type$' (permanent str account reg2)
+ **/
+int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) {
+ struct script_reg_str *p = NULL;
+ const char *regname = script->get_str( script_getvarid(reg) );
+ unsigned int index = script_getvaridx(reg);
-int pc_setregistry_str(struct map_session_data *sd,const char *reg,const char *val,int type)
-{
- struct global_reg *sd_reg;
- int i,*max, regmax;
-
- nullpo_ret(sd);
- if (reg[strlen(reg)-1] != '$') {
- ShowError("pc_setregistry_str : reg %s must be string (end in '$') to use this!\n", reg);
- return 0;
- }
-
- switch (type) {
- case 3: //Char reg
- sd_reg = sd->save_reg.global;
- max = &sd->save_reg.global_num;
- regmax = GLOBAL_REG_NUM;
- break;
- case 2: //Account reg
- sd_reg = sd->save_reg.account;
- max = &sd->save_reg.account_num;
- regmax = ACCOUNT_REG_NUM;
- break;
- case 1: //Account2 reg
- sd_reg = sd->save_reg.account2;
- max = &sd->save_reg.account2_num;
- regmax = ACCOUNT_REG2_NUM;
- break;
- default:
- return 0;
- }
- if (*max == -1) {
- ShowError("pc_setregistry_str : refusing to set %s (type %d) until vars are received.\n", reg, type);
+ if ( !pc->reg_load && !sd->vars_ok ) {
+ ShowError("pc_setregistry_str : refusing to set %s until vars are received.\n", regname);
return 0;
}
- // delete reg
- if (!val || strcmp(val,"")==0)
- {
- ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 );
- if( i < *max )
- {
- if (i != *max - 1)
- memcpy(&sd_reg[i], &sd_reg[*max - 1], sizeof(struct global_reg));
- memset(&sd_reg[*max - 1], 0, sizeof(struct global_reg));
- (*max)--;
- sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved"
- if (type!=3) intif->saveregistry(sd,type);
+ if( (p = i64db_get(sd->var_db, reg) ) ) {
+ if( val[0] ) {
+ if( p->value )
+ aFree(p->value);
+ else if ( index ) /* a entry that was deleted, so we reset */
+ script->array_update(&sd->array_db,reg,false);
+ p->value = aStrdup(val);
+ } else {
+ p->value = NULL;
+ if( index )
+ script->array_update(&sd->array_db,reg,true);
}
- return 1;
- }
+ if( !pc->reg_load )
+ p->flag.update = 1;/* either way, it will require either delete or replace */
+ } else if( val[0] ) {
+ DBData prev;
- // change value if found
- ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 );
- if( i < *max )
- {
- safestrncpy(sd_reg[i].value, val, sizeof(sd_reg[i].value));
- sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved"
- if (type!=3) intif->saveregistry(sd,type);
- return 1;
- }
+ if( index )
+ script->array_update(&sd->array_db,reg,false);
- // add value if not found
- if (i < regmax) {
- memset(&sd_reg[i], 0, sizeof(struct global_reg));
- safestrncpy(sd_reg[i].str, reg, sizeof(sd_reg[i].str));
- safestrncpy(sd_reg[i].value, val, sizeof(sd_reg[i].value));
- (*max)++;
- sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved"
- if (type!=3) intif->saveregistry(sd,type);
- return 1;
+ p = ers_alloc(pc->str_reg_ers, struct script_reg_str);
+
+ p->value = aStrdup(val);
+ if( !pc->reg_load )
+ p->flag.update = 1;
+ p->flag.type = 1;
+
+ if( sd->var_db->put(sd->var_db,DB->i642key(reg),DB->ptr2data(p),&prev) ) {
+ p = DB->data2ptr(&prev);
+ if( p->value )
+ aFree(p->value);
+ ers_free(pc->str_reg_ers, p);
+ }
}
-
- ShowError("pc_setregistry : couldn't set %s, limit of registries reached (%d)\n", reg, regmax);
-
- return 0;
+
+ if( !pc->reg_load && p )
+ sd->vars_dirty = true;
+
+ return 1;
}
/*==========================================
@@ -10556,6 +10468,9 @@ void do_final_pc(void) {
pcg->final();
ers_destroy(pc->sc_display_ers);
+ ers_destroy(pc->num_reg_ers);
+ ers_destroy(pc->str_reg_ers);
+
return;
}
@@ -10599,6 +10514,12 @@ void do_init_pc(bool minimal) {
pcg->init();
pc->sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:sc_display_ers", ERS_OPT_NONE);
+ pc->num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.c::num_reg_ers", ERS_OPT_CLEAN);
+ pc->str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.c::str_reg_ers", ERS_OPT_CLEAN);
+
+ ers_chunk_size(pc->sc_display_ers, 150);
+ ers_chunk_size(pc->num_reg_ers, 300);
+ ers_chunk_size(pc->str_reg_ers, 50);
}
/*=====================================
* Default Functions : pc.h
@@ -10613,7 +10534,6 @@ void pc_defaults(void) {
};
unsigned int equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_GARMENT,EQP_AMMO, EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L };
-
pc = &pc_s;
/* vars */
@@ -10642,6 +10562,11 @@ void pc_defaults(void) {
pc->sc_display_ers = NULL;
/* */
pc->expiration_tid = INVALID_TIMER;
+ /* */
+ pc->num_reg_ers = NULL;
+ pc->str_reg_ers = NULL;
+ /* */
+ pc->reg_load = false;
/* funcs */
pc->init = do_init_pc;
pc->final = do_final_pc;
diff --git a/src/map/pc.h b/src/map/pc.h
index 2f143f15c..f64b20945 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -139,7 +139,6 @@ struct map_session_data {
unsigned int abra_flag : 2; // Abracadabra bugfix by Aru
unsigned int autocast : 1; // Autospell flag [Inkfish]
unsigned int autotrade : 1; //By Fantik
- unsigned int reg_dirty : 4; //By Skotlex (marks whether registry variables have been saved or not yet)
unsigned int showdelay :1;
unsigned int showexp :1;
unsigned int showzeny :1;
@@ -203,7 +202,6 @@ struct map_session_data {
unsigned int extra_temp_permissions; /* permissions from @addperm */
struct mmo_charstatus status;
- struct registry save_reg;
struct item_data* inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups)
short equip_index[EQI_MAX];
unsigned int weight,max_weight;
@@ -363,10 +361,6 @@ struct map_session_data {
short mission_mobid; //Stores the target mob_id for TK_MISSION
int die_counter; //Total number of times you've died
int devotion[5]; //Stores the account IDs of chars devoted to.
- int reg_num; //Number of registries (type numeric)
- int regstr_num; //Number of registries (type string)
- struct script_reg *reg;
- struct script_regstr *regstr;
int trade_partner;
struct {
struct {
@@ -531,6 +525,16 @@ struct map_session_data {
struct {
unsigned int second,third;
} sktree;
+
+ /**
+ * Account/Char variables & array control of those variables
+ **/
+ DBMap *var_db;
+ DBMap *array_db;
+ unsigned char vars_received;/* char loading is only complete when you get it all. */
+ bool vars_ok;
+ bool vars_dirty;
+
// temporary debugging of bug #3504
const char* delunit_prevfile;
int delunit_prevline;
@@ -672,18 +676,18 @@ enum equip_pos {
#define pc_checkoverhp(sd) ((sd)->battle_status.hp == (sd)->battle_status.max_hp)
#define pc_checkoversp(sd) ((sd)->battle_status.sp == (sd)->battle_status.max_sp)
-#define pc_readglobalreg(sd,reg) (pc->readregistry((sd),(reg),3))
-#define pc_setglobalreg(sd,reg,val) (pc->setregistry((sd),(reg),(val),3))
-#define pc_readglobalreg_str(sd,reg) (pc->readregistry_str((sd),(reg),3))
-#define pc_setglobalreg_str(sd,reg,val) (pc->setregistry_str((sd),(reg),(val),3))
-#define pc_readaccountreg(sd,reg) (pc->readregistry((sd),(reg),2))
-#define pc_setaccountreg(sd,reg,val) (pc->setregistry((sd),(reg),(val),2))
-#define pc_readaccountregstr(sd,reg) (pc->readregistry_str((sd),(reg),2))
-#define pc_setaccountregstr(sd,reg,val) (pc->setregistry_str((sd),(reg),(val),2))
-#define pc_readaccountreg2(sd,reg) (pc->readregistry((sd),(reg),1))
-#define pc_setaccountreg2(sd,reg,val) (pc->setregistry((sd),(reg),(val),1))
-#define pc_readaccountreg2str(sd,reg) (pc->readregistry_str((sd),(reg),1))
-#define pc_setaccountreg2str(sd,reg,val) (pc->setregistry_str((sd),(reg),(val),1))
+#define pc_readglobalreg(sd,reg) (pc->readregistry((sd),(reg)))
+#define pc_setglobalreg(sd,reg,val) (pc->setregistry((sd),(reg),(val)))
+#define pc_readglobalreg_str(sd,reg) (pc->readregistry_str((sd),(reg)))
+#define pc_setglobalreg_str(sd,reg,val) (pc->setregistry_str((sd),(reg),(val)))
+#define pc_readaccountreg(sd,reg) (pc->readregistry((sd),(reg)))
+#define pc_setaccountreg(sd,reg,val) (pc->setregistry((sd),(reg),(val)))
+#define pc_readaccountregstr(sd,reg) (pc->readregistry_str((sd),(reg)))
+#define pc_setaccountregstr(sd,reg,val) (pc->setregistry_str((sd),(reg),(val)))
+#define pc_readaccountreg2(sd,reg) (pc->readregistry((sd),(reg)))
+#define pc_setaccountreg2(sd,reg,val) (pc->setregistry((sd),(reg),(val)))
+#define pc_readaccountreg2str(sd,reg) (pc->readregistry_str((sd),(reg)))
+#define pc_setaccountreg2str(sd,reg,val) (pc->setregistry_str((sd),(reg),(val)))
/* pc_groups easy access */
#define pc_get_group_level(sd) ( (sd)->group->level )
@@ -772,6 +776,13 @@ struct pc_interface {
struct eri *sc_display_ers;
/* global expiration timer id */
int expiration_tid;
+ /**
+ * ERS for the bulk of pc vars
+ **/
+ struct eri *num_reg_ers;
+ struct eri *str_reg_ers;
+ /* */
+ bool reg_load;
/* funcs */
void (*init) (bool minimal);
void (*final) (void);
@@ -908,14 +919,14 @@ struct pc_interface {
int (*readparam) (struct map_session_data *sd,int type);
int (*setparam) (struct map_session_data *sd,int type,int val);
- int (*readreg) (struct map_session_data *sd,int reg);
- int (*setreg) (struct map_session_data *sd,int reg,int val);
- char * (*readregstr) (struct map_session_data *sd,int reg);
- int (*setregstr) (struct map_session_data *sd,int reg,const char *str);
- int (*readregistry) (struct map_session_data *sd,const char *reg,int type);
- int (*setregistry) (struct map_session_data *sd,const char *reg,int val,int type);
- char * (*readregistry_str) (struct map_session_data *sd,const char *reg,int type);
- int (*setregistry_str) (struct map_session_data *sd,const char *reg,const char *val,int type);
+ int (*readreg) (struct map_session_data *sd, int64 reg);
+ void (*setreg) (struct map_session_data *sd, int64 reg,int val);
+ char * (*readregstr) (struct map_session_data *sd, int64 reg);
+ void (*setregstr) (struct map_session_data *sd, int64 reg, const char *str);
+ int (*readregistry) (struct map_session_data *sd, int64 reg);
+ int (*setregistry) (struct map_session_data *sd, int64 reg, int val);
+ char * (*readregistry_str) (struct map_session_data *sd, int64 reg);
+ int (*setregistry_str) (struct map_session_data *sd, int64 reg, const char *val);
int (*addeventtimer) (struct map_session_data *sd,int tick,const char *name);
int (*deleventtimer) (struct map_session_data *sd,const char *name);
diff --git a/src/map/script.c b/src/map/script.c
index 8bd4bc028..21d4d289c 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -212,10 +212,7 @@ void script_reportdata(struct script_data* data)
case C_NAME:// reference
if( reference_tovariable(data) ) {// variable
const char* name = reference_getname(data);
- if( not_array_variable(*name) )
- ShowDebug("Data: variable name='%s'\n", name);
- else
- ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data));
+ ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data));
} else if( reference_toconstant(data) ) {// constant
ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data));
} else if( reference_toparam(data) ) {// param
@@ -2501,9 +2498,9 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
break;
case '#':
if( name[1] == '#' )
- data->u.str = pc_readaccountreg2str(sd, name);// global
+ data->u.str = pc_readaccountreg2str(sd, data->u.num);// global
else
- data->u.str = pc_readaccountregstr(sd, name);// local
+ data->u.str = pc_readaccountregstr(sd, data->u.num);// local
break;
case '.':
{
@@ -2512,21 +2509,21 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
st->stack->var_function : // instance/scope variable
st->script->script_vars; // npc variable
if( n )
- data->u.str = (char*)idb_get(n,reference_getuid(data));
+ data->u.str = (char*)i64db_get(n,reference_getuid(data));
else
data->u.str = NULL;
}
break;
case '\'':
if ( st->instance_id >= 0 ) {
- data->u.str = (char*)idb_get(instance->list[st->instance_id].vars,reference_getuid(data));
+ data->u.str = (char*)i64db_get(instance->list[st->instance_id].vars,reference_getuid(data));
} else {
ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to \"\"\n", name);
data->u.str = NULL;
}
break;
default:
- data->u.str = pc_readglobalreg_str(sd, name);
+ data->u.str = pc_readglobalreg_str(sd, data->u.num);
break;
}
@@ -2556,9 +2553,9 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
break;
case '#':
if( name[1] == '#' )
- data->u.num = pc_readaccountreg2(sd, name);// global
+ data->u.num = pc_readaccountreg2(sd, data->u.num);// global
else
- data->u.num = pc_readaccountreg(sd, name);// local
+ data->u.num = pc_readaccountreg(sd, data->u.num);// local
break;
case '.':
{
@@ -2567,21 +2564,21 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
st->stack->var_function : // instance/scope variable
st->script->script_vars; // npc variable
if( n )
- data->u.num = (int)idb_iget(n,reference_getuid(data));
+ data->u.num = (int)i64db_iget(n,reference_getuid(data));
else
data->u.num = 0;
}
break;
case '\'':
if( st->instance_id >= 0 )
- data->u.num = (int)idb_iget(instance->list[st->instance_id].vars,reference_getuid(data));
+ data->u.num = (int)i64db_iget(instance->list[st->instance_id].vars,reference_getuid(data));
else {
ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to 0\n", name);
data->u.num = 0;
}
break;
default:
- data->u.num = pc_readglobalreg(sd, name);
+ data->u.num = pc_readglobalreg(sd, data->u.num);
break;
}
@@ -2592,63 +2589,245 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
/// Retrieves the value of a reference identified by uid (variable, constant, param)
/// The value is left in the top of the stack and needs to be removed manually.
-void* get_val2(struct script_state* st, int uid, struct DBMap** ref) {
+void* get_val2(struct script_state* st, int64 uid, struct DBMap** ref) {
struct script_data* data;
script->push_val(st->stack, C_NAME, uid, ref);
data = script_getdatatop(st, -1);
script->get_val(st, data);
return (data->type == C_INT ? (void*)__64BPTRSIZE(data->u.num) : (void*)__64BPTRSIZE(data->u.str));
}
+/**
+ * Returns array size by ID
+ **/
+unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name) {
+ struct script_array *sa = NULL;
+ struct DBMap *src = script->array_src(st, sd, name);
+
+ if( src )
+ sa = idb_get(src, script->search_str(name));
+
+ return sa ? sa->size : 0;
+}
+/**
+ * Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size)
+ **/
+unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name) {
+ struct script_array *sa = NULL;
+ struct DBMap *src = script->array_src(st, sd, name);
+
+ if( src && ( sa = idb_get(src, script->search_str(name)) ) ) {
+ unsigned int i, highest_key = 0;
+
+ for(i = 0; i < sa->size; i++) {
+ if( sa->members[i] > highest_key )
+ highest_key = sa->members[i];
+ }
+
+ return highest_key + 1;
+ }
+
+ return 0;
+}
+int script_free_array_db(DBKey key, DBData *data, va_list ap) {
+ struct script_array *sa = DB->data2ptr(data);
+ aFree(sa->members);
+ ers_free(script->array_ers, sa);
+ return 0;
+}
+/**
+ * Clears script_array and removes it from script->array_db
+ **/
+void script_array_delete(struct DBMap *src, struct script_array *sa) {
+ aFree(sa->members);
+ idb_remove(src, sa->id);
+ ers_free(script->array_ers, sa);
+}
+/**
+ * Removes a member from a script_array list
+ *
+ * @param idx the index of the member in script_array struct list, not of the actual array member
+ **/
+void script_array_remove_member(struct DBMap *src,struct script_array *sa, unsigned int idx) {
+ unsigned int i, cursor;
+
+ /* its the only member left, no need to do anything other than delete the array data */
+ if( sa->size == 1 ) {
+ script->array_delete(src,sa);
+ return;
+ }
+
+ sa->members[idx] = UINT_MAX;
+
+ for(i = 0, cursor = 0; i < sa->size; i++) {
+ if( sa->members[i] == UINT_MAX )
+ continue;
+ if( i != cursor )
+ sa->members[cursor] = sa->members[i];
+ cursor++;
+ }
+
+ sa->size = cursor;
+}
+/**
+ * Appends a new array index to the list in script_array
+ *
+ * @param idx the index of the array member being inserted
+ **/
+void script_array_add_member(struct script_array *sa, unsigned int idx) {
+
+ RECREATE(sa->members, unsigned int, ++sa->size);
+
+ sa->members[sa->size - 1] = idx;
+}
+/**
+ * Obtains the source of the array database for this type and scenario
+ * Initializes such database when not yet initialised.
+ **/
+struct DBMap *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name) {
+ struct DBMap **src = NULL;
+
+ switch( name[0] ) {
+ /* from player */
+ default: /* char reg */
+ case '@':/* temp char reg */
+ case '#':/* account reg */
+ src = &sd->array_db;
+ break;
+ case '$':/* map reg */
+ src = &mapreg->array_db;
+ break;
+ case '.':/* npc/script */
+ src = (name[1] == '@') ? &st->stack->array_function_db : &st->script->script_arrays_db;
+ break;
+ case '\'':/* instance */
+ if( st->instance_id >= 0 ) {
+ src = &instance->list[st->instance_id].array_db;
+ }
+ break;
+ }
+
+ if( src ) {
+ if( !*src )
+ *src = idb_alloc(DB_OPT_BASE);
+ return *src;
+ }
+
+ return NULL;
+}
+/**
+ * Processes a array member modification, and update data accordingly
+ **/
+void script_array_update(struct DBMap **src, int64 num, bool empty) {
+ struct script_array *sa = NULL;
+ int id = script_getvarid(num);
+ unsigned int index = script_getvaridx(num);
+
+ if( !*src ) {
+ *src = idb_alloc(DB_OPT_BASE);
+ } else {
+ sa = idb_get(*src, id);
+ }
+
+ if( sa ) {
+ unsigned int i;
+
+ /* search */
+ for(i = 0; i < sa->size; i++) {
+ if( sa->members[i] == index )
+ break;
+ }
+
+ /* if existent */
+ if( i != sa->size ) {
+ /* if empty, we gotta remove it */
+ if( empty ) {
+ script->array_remove_member(*src,sa,i);
+ }
+ } else if( !empty ) { /* new entry */
+ script->array_add_member(sa,index);
+ /* we do nothing if its empty, no point in modifying array data for a new empty member */
+ }
+ } else if ( !empty ) {/* we only move to create if not empty */
+ sa = ers_alloc(script->array_ers, struct script_array);
+ sa->id = id;
+ script->array_add_member(sa,index);
+ idb_put(*src, id, sa);
+ }
+}
/*==========================================
* Stores the value of a script variable
* Return value is 0 on fail, 1 on success.
+ * TODO: return values are screwed up, have been for some time (reaad: years), e.g. some functions return 1 failure and success.
*------------------------------------------*/
-int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, const void* value, struct DBMap** ref)
-{
+int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, const void* value, struct DBMap** ref) {
char prefix = name[0];
+
+ if( is_string_variable(name) ) {// string variable
+ const char *str = (const char*)value;
- if( is_string_variable(name) )
- {// string variable
- const char* str = (const char*)value;
switch (prefix) {
- case '@':
- return pc->setregstr(sd, num, str);
- case '$':
- return mapreg->setregstr(num, str);
- case '#':
- return (name[1] == '#') ?
- pc_setaccountreg2str(sd, name, str) :
- pc_setaccountregstr(sd, name, str);
- case '.':
- {
- struct DBMap* n;
- n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars;
- if( n ) {
- idb_remove(n, num);
- if (str[0]) idb_put(n, num, aStrdup(str));
+ case '@':
+ pc->setregstr(sd, num, str);
+ return 1;
+ case '$':
+ return mapreg->setregstr(num, str);
+ case '#':
+ return (name[1] == '#') ?
+ pc_setaccountreg2str(sd, num, str) :
+ pc_setaccountregstr(sd, num, str);
+ case '.':
+ {
+ struct DBMap* n;
+ n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars;
+ if( n ) {
+ if (str[0]) {
+ i64db_put(n, num, aStrdup(str));
+ if( script_getvaridx(num) )
+ script->array_update(
+ (name[1] == '@') ?
+ &st->stack->array_function_db :
+ &st->script->script_arrays_db,
+ num,
+ false);
+ } else {
+ i64db_remove(n, num);
+ if( script_getvaridx(num) )
+ script->array_update(
+ (name[1] == '@') ?
+ &st->stack->array_function_db :
+ &st->script->script_arrays_db,
+ num,
+ true);
+ }
+ }
}
- }
- return 1;
- case '\'':
- if( st->instance_id >= 0 ) {
- idb_remove(instance->list[st->instance_id].vars, num);
- if( str[0] ) idb_put(instance->list[st->instance_id].vars, num, aStrdup(str));
- }
- return 1;
- default:
- return pc_setglobalreg_str(sd, name, str);
+ return 1;
+ case '\'':
+ if( st->instance_id >= 0 ) {
+ if( str[0] ) {
+ i64db_put(instance->list[st->instance_id].vars, num, aStrdup(str));
+ if( script_getvaridx(num) )
+ script->array_update(&instance->list[st->instance_id].array_db,num,false);
+ } else {
+ i64db_remove(instance->list[st->instance_id].vars, num);
+ if( script_getvaridx(num) )
+ script->array_update(&instance->list[st->instance_id].array_db,num,true);
+ }
+ } else {
+ ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
+ script_reportsrc(st);
+ }
+ return 1;
+ default:
+ return pc_setglobalreg_str(sd, num, str);
}
- }
- else
- {// integer variable
+ } else {// integer variable
int val = (int)__64BPTRSIZE(value);
- if(script->str_data[num&0x00ffffff].type == C_PARAM)
- {
- if( pc->setparam(sd, script->str_data[num&0x00ffffff].val, val) == 0 )
- {
- if( st != NULL )
- {
+
+ if(script->str_data[script_getvarid(num)].type == C_PARAM) {
+ if( pc->setparam(sd, script->str_data[script_getvarid(num)].val, val) == 0 ) {
+ if( st != NULL ) {
ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val);
script->reportsrc(st);
st->state = END;
@@ -2659,34 +2838,60 @@ int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, cons
}
switch (prefix) {
- case '@':
- return pc->setreg(sd, num, val);
- case '$':
- return mapreg->setreg(num, val);
- case '#':
- return (name[1] == '#') ?
- pc_setaccountreg2(sd, name, val) :
- pc_setaccountreg(sd, name, val);
- case '.':
- {
- struct DBMap* n;
- n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars;
- if( n ) {
- idb_remove(n, num);
- if( val != 0 )
- idb_iput(n, num, val);
+ case '@':
+ pc->setreg(sd, num, val);
+ return 1;
+ case '$':
+ return mapreg->setreg(num, val);
+ case '#':
+ return (name[1] == '#') ?
+ pc_setaccountreg2(sd, num, val) :
+ pc_setaccountreg(sd, num, val);
+ case '.':
+ {
+ struct DBMap* n;
+ n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars;
+ if( n ) {
+ if( val != 0 ) {
+ i64db_iput(n, num, val);
+ if( script_getvaridx(num) )
+ script->array_update(
+ (name[1] == '@') ?
+ &st->stack->array_function_db :
+ &st->script->script_arrays_db,
+ num,
+ false);
+ } else {
+ i64db_remove(n, num);
+ if( script_getvaridx(num) )
+ script->array_update(
+ (name[1] == '@') ?
+ &st->stack->array_function_db :
+ &st->script->script_arrays_db,
+ num,
+ true);
+ }
+ }
}
- }
- return 1;
- case '\'':
- if( st->instance_id >= 0 ) {
- idb_remove(instance->list[st->instance_id].vars, num);
- if( val != 0 )
- idb_iput(instance->list[st->instance_id].vars, num, val);
- }
- return 1;
- default:
- return pc_setglobalreg(sd, name, val);
+ return 1;
+ case '\'':
+ if( st->instance_id >= 0 ) {
+ if( val != 0 ) {
+ i64db_iput(instance->list[st->instance_id].vars, num, val);
+ if( script_getvaridx(num) )
+ script->array_update(&instance->list[st->instance_id].array_db,num,false);
+ } else {
+ i64db_remove(instance->list[st->instance_id].vars, num);
+ if( script_getvaridx(num) )
+ script->array_update(&instance->list[st->instance_id].array_db,num,true);
+ }
+ } else {
+ ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
+ script_reportsrc(st);
+ }
+ return 1;
+ default:
+ return pc_setglobalreg(sd, num, val);
}
}
}
@@ -2712,7 +2917,7 @@ const char* conv_str(struct script_state* st, struct script_data* data)
else if( data_isint(data) )
{// int -> string
CREATE(p, char, ITEM_NAME_LENGTH);
- snprintf(p, ITEM_NAME_LENGTH, "%d", data->u.num);
+ snprintf(p, ITEM_NAME_LENGTH, "%lld", data->u.num);
p[ITEM_NAME_LENGTH-1] = '\0';
data->type = C_STR;
data->u.str = p;
@@ -2786,7 +2991,7 @@ int conv_num(struct script_state* st, struct script_data* data) {
data->u.num = 0;
}
#endif
- return data->u.num;
+ return (int)data->u.num;
}
//
@@ -2803,7 +3008,7 @@ void stack_expand(struct script_stack* stack) {
}
/// Pushes a value into the stack (with reference)
-struct script_data* push_val(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref) {
+struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct DBMap** ref) {
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = type;
@@ -2932,6 +3137,8 @@ void script_free_vars(struct DBMap* var_storage) {
void script_free_code(struct script_code* code)
{
script->free_vars( code->script_vars );
+ if( code->script_arrays_db )
+ code->script_arrays_db->destroy(code->script_arrays_db,script->array_free_db);
aFree( code->script_buf );
aFree( code );
}
@@ -2952,7 +3159,8 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos,
st->stack->sp_max = 64;
CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max);
st->stack->defsp = st->stack->sp;
- st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA);
+ st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA);
+ st->stack->array_function_db = NULL;
st->state = RUN;
st->script = rootscript;
st->pos = pos;
@@ -2962,7 +3170,7 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos,
st->npc_item_flag = battle_config.item_enabled_npc;
if( !st->script->script_vars )
- st->script->script_vars = idb_alloc(DB_OPT_RELEASE_DATA);
+ st->script->script_vars = i64db_alloc(DB_OPT_RELEASE_DATA);
st->id = script->next_id++;
script->active_scripts++;
@@ -2985,14 +3193,22 @@ void script_free_state(struct script_state* st) {
timer->delete(st->sleep.timer, script->run_timer);
if( st->stack ) {
script->free_vars(st->stack->var_function);
+ if( st->stack->array_function_db )
+ st->stack->array_function_db->destroy(st->stack->array_function_db,script->array_free_db);
script->pop_stack(st, 0, st->stack->sp);
aFree(st->stack->stack_data);
ers_free(script->stack_ers, st->stack);
st->stack = NULL;
}
- if( st->script && st->script->script_vars && !db_size(st->script->script_vars) ) {
- script->free_vars(st->script->script_vars);
- st->script->script_vars = NULL;
+ if( st->script ) {
+ if( st->script->script_vars && !db_size(st->script->script_vars) ) {
+ script->free_vars(st->script->script_vars);
+ st->script->script_vars = NULL;
+ }
+ if( st->script->script_arrays_db && !db_size(st->script->script_arrays_db) ) {
+ script->free_vars(st->script->script_arrays_db);
+ st->script->script_arrays_db = NULL;
+ }
}
st->pos = -1;
idb_remove(script->st_db, st->id);
@@ -3037,20 +3253,6 @@ int get_num(unsigned char *scriptbuf,int *pos)
return i+((scriptbuf[(*pos)++]&0x7f)<<j);
}
-/*==========================================
- * Remove the value from the stack
- *------------------------------------------*/
-int pop_val(struct script_state* st)
-{
- if(st->stack->sp<=0)
- return 0;
- st->stack->sp--;
- script->get_val(st,&(st->stack->stack_data[st->stack->sp]));
- if(st->stack->stack_data[st->stack->sp].type==C_INT)
- return st->stack->stack_data[st->stack->sp].u.num;
- return 0;
-}
-
/// Ternary operators
/// test ? if_true : if_false
void op_3(struct script_state* st, int op)
@@ -3064,7 +3266,7 @@ void op_3(struct script_state* st, int op)
if( data_isstring(data) )
flag = data->u.str[0];// "" -> false
else if( data_isint(data) )
- flag = data->u.num;// 0 -> false
+ flag = data->u.num == 0 ? 0 : 1;// 0 -> false
else
{
ShowError("script:op_3: invalid data for the ternary operator test\n");
@@ -3234,8 +3436,8 @@ void op_2(struct script_state *st, int op)
}
else if( data_isint(left) && data_isint(right) )
{// ii => op_2num
- int i1 = left->u.num;
- int i2 = right->u.num;
+ int i1 = (int)left->u.num;
+ int i2 = (int)right->u.num;
script_removetop(st, leftref.type == C_NOP ? -2 : -1, 0);
script->op_2num(st, op, i1, i2);
@@ -3277,19 +3479,18 @@ void op_1(struct script_state* st, int op)
return;
}
- i1 = data->u.num;
+ i1 = (int)data->u.num;
script_removetop(st, -1, 0);
- switch( op )
- {
- case C_NEG: i1 = -i1; break;
- case C_NOT: i1 = ~i1; break;
- case C_LNOT: i1 = !i1; break;
- default:
- ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1);
- script->reportsrc(st);
- script_pushnil(st);
- st->state = END;
- return;
+ switch( op ) {
+ case C_NEG: i1 = -i1; break;
+ case C_NOT: i1 = ~i1; break;
+ case C_LNOT: i1 = !i1; break;
+ default:
+ ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1);
+ script->reportsrc(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
}
script_pushint(st, i1);
}
@@ -3400,7 +3601,7 @@ int run_func(struct script_state *st)
data = &st->stack->stack_data[st->start];
if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC )
- func = data->u.num;
+ func = (int)data->u.num;
else
{
ShowError("script:run_func: not a buildin command.\n");
@@ -3418,7 +3619,7 @@ int run_func(struct script_state *st)
if (!(script->str_data[func].func(st))) //Report error
script->reportsrc(st);
} else {
- ShowError("script:run_func: '%s' (id=%d type=%s) has no C function. please report this!!!\n", script->get_str(func), func, script->op2name(script->str_data[func].type));
+ ShowError("script:run_func: '%s' (id=%lld type=%s) has no C function. please report this!!!\n", script->get_str(func), func, script->op2name(script->str_data[func].type));
script->reportsrc(st);
st->state = END;
}
@@ -3723,10 +3924,8 @@ void run_script_main(struct script_state *st) {
}
//Restore previous script if any.
script->detach_state(st, true);
- if (sd->state.reg_dirty&2)
- intif->saveregistry(sd,2);
- if (sd->state.reg_dirty&1)
- intif->saveregistry(sd,1);
+ if (sd->vars_dirty)
+ intif->saveregistry(sd);
}
script->free_state(st);
st = NULL;
@@ -3813,70 +4012,99 @@ void script_add_autobonus(const char *autobonus)
/// resets a temporary character array variable to given value
-void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value)
-{
+void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) {
+ struct script_array *sa = NULL;
+ struct DBMap *src = NULL;
+ unsigned int i, *list = NULL, size = 0;
int key;
- uint8 idx;
-
- if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
- {
- ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
- return;
- }
key = script->add_str(varname);
-
- if( is_string_variable(varname) )
- {
- for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
- {
- pc->setregstr(sd, reference_uid(key, idx), (const char*)value);
- }
- }
- else
- {
- for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
- {
- pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value));
- }
+
+ if( !(src = script->array_src(NULL,sd,varname) ) )
+ return;
+
+ if( !(sa = idb_get(src, key)) ) /* non-existent array, nothing to empty */
+ return;
+
+ size = sa->size;
+ list = script->array_cpy_list(sa);
+
+ for(i = 0; i < size; i++) {
+ script->set_reg(NULL,sd,reference_uid(key, list[i]),varname,value,NULL);
}
}
/// sets a temporary character array variable element idx to given value
/// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set.
-void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache)
-{
+void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache) {
int key;
-
- if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
- {
- ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
- return;
- }
-
- if( idx >= SCRIPT_MAX_ARRAYSIZE )
- {
- ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id);
+
+ if( idx >= SCRIPT_MAX_ARRAYSIZE ) {
+ ShowError("script_setarray_pc: Variable '%s' has invalid index '%u' (char_id=%d).\n", varname, idx, sd->status.char_id);
return;
}
key = ( refcache && refcache[0] ) ? refcache[0] : script->add_str(varname);
-
- if( is_string_variable(varname) )
- {
- pc->setregstr(sd, reference_uid(key, idx), (const char*)value);
- }
- else
- {
- pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value));
- }
-
+
+ script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL);
+
if( refcache )
{// save to avoid repeated script->add_str calls
refcache[0] = key;
}
}
+/**
+ * Clears persistent variables from memory
+ **/
+int script_reg_destroy(DBKey key, DBData *data, va_list ap) {
+ void *src;
+
+ if( data->type != DB_DATA_PTR )/* got no need for those! */
+ return 0;
+
+ src = DB->data2ptr(data);
+
+ if( ((struct script_reg_state*)src)->type ) {
+ struct script_reg_str *p = src;
+
+ if( p->value )
+ aFree(p->value);
+
+ ers_free(pc->str_reg_ers,p);
+ } else {
+ ers_free(pc->num_reg_ers,(struct script_reg_num*)src);
+ }
+
+ return 0;
+}
+/**
+ * Clears a single persistent variable
+ **/
+void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) {
+ i64db_remove(sd->var_db, reg);
+
+ if( data->type ) {
+ struct script_reg_str *p = (struct script_reg_str*)data;
+
+ if( p->value )
+ aFree(p->value);
+
+ ers_free(pc->str_reg_ers,p);
+ } else {
+ ers_free(pc->num_reg_ers,(struct script_reg_num*)data);
+ }
+}
+unsigned int *script_array_cpy_list(struct script_array *sa) {
+ if( sa->size > script->generic_ui_array_size )
+ script->generic_ui_array_expand(sa->size);
+ memcpy(script->generic_ui_array, sa->members, sizeof(unsigned int)*sa->size);
+ return script->generic_ui_array;
+}
+void script_generic_ui_array_expand (unsigned int plus) {
+ script->generic_ui_array_size += plus + 100;
+ RECREATE(script->generic_ui_array, unsigned int, script->generic_ui_array_size);
+}
/*==========================================
* Destructor
*------------------------------------------*/
@@ -4005,6 +4233,11 @@ void do_final_script(void) {
if( script->labels != NULL )
aFree(script->labels);
+
+ ers_destroy(script->array_ers);
+
+ if( script->generic_ui_array )
+ aFree(script->generic_ui_array);
}
/*==========================================
* Initialization
@@ -4016,6 +4249,7 @@ void do_init_script(bool minimal) {
script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_CLEAN);
script->stack_ers = ers_new(sizeof(struct script_stack), "script.c::script_stack", ERS_OPT_NONE);
+ script->array_ers = ers_new(sizeof(struct script_array), "script.c::array_ers", ERS_OPT_CLEAN|ERS_OPT_CLEAR);
ers_chunk_size(script->st_ers, 10);
ers_chunk_size(script->stack_ers, 10);
@@ -4073,7 +4307,7 @@ const char *script_getfuncname(struct script_state *st) {
data = &st->stack->stack_data[st->start];
if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC )
- return script->get_str(data->u.num);
+ return script->get_str(script_getvarid(data->u.num));
return NULL;
}
@@ -4568,7 +4802,7 @@ BUILDIN(callfunc)
st->script = scr;
st->stack->defsp = st->stack->sp;
st->state = GOTO;
- st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA);
+ st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA);
return true;
}
@@ -4617,7 +4851,7 @@ BUILDIN(callsub)
st->pos = pos;
st->stack->defsp = st->stack->sp;
st->state = GOTO;
- st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA);
+ st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA);
return true;
}
@@ -5150,7 +5384,7 @@ BUILDIN(input)
{
TBL_PC* sd;
struct script_data* data;
- int uid;
+ int64 uid;
const char* name;
int min;
int max;
@@ -5214,7 +5448,7 @@ BUILDIN(setr) {
TBL_PC* sd = NULL;
struct script_data* data;
//struct script_data* datavalue;
- int num;
+ int64 num;
const char* name;
char prefix;
@@ -5292,34 +5526,6 @@ BUILDIN(setr) {
/// Array variables
///
-/// Returns the size of the specified array
-int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isstring, struct DBMap** ref)
-{
- int32 ret = idx;
-
- if( isstring )
- {
- for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
- {
- char* str = (char*)script->get_val2(st, reference_uid(id, idx), ref);
- if( str && *str )
- ret = idx + 1;
- script_removetop(st, -1, 0);
- }
- }
- else
- {
- for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
- {
- int32 num = (int32)__64BPTRSIZE(script->get_val2(st, reference_uid(id, idx), ref));
- if( num )
- ret = idx + 1;
- script_removetop(st, -1, 0);
- }
- }
- return ret;
-}
-
/// Sets values of an array, from the starting index.
/// ex: setarray arr[1],1,2,3;
///
@@ -5346,13 +5552,6 @@ BUILDIN(setarray)
id = reference_getid(data);
start = reference_getindex(data);
name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:setarray: illegal scope\n");
- script->reportdata(data);
- st->state = END;
- return false;// not supported
- }
if( not_server_variable(*name) )
{
@@ -5404,13 +5603,6 @@ BUILDIN(cleararray)
id = reference_getid(data);
start = reference_getindex(data);
name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:cleararray: illegal scope\n");
- script->reportdata(data);
- st->state = END;
- return false;// not supported
- }
if( not_server_variable(*name) )
{
@@ -5469,14 +5661,6 @@ BUILDIN(copyarray)
idx2 = reference_getindex(data2);
name1 = reference_getname(data1);
name2 = reference_getname(data2);
- if( not_array_variable(*name1) || not_array_variable(*name2) )
- {
- ShowError("script:copyarray: illegal scope\n");
- script->reportdata(data1);
- script->reportdata(data2);
- st->state = END;
- return false;// not supported
- }
if( is_string_variable(name1) != is_string_variable(name2) )
{
@@ -5534,7 +5718,6 @@ BUILDIN(copyarray)
BUILDIN(getarraysize)
{
struct script_data* data;
- const char* name;
data = script_getdata(st, 2);
if( !data_isreference(data) )
@@ -5546,19 +5729,12 @@ BUILDIN(getarraysize)
return false;// not a variable
}
- name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:getarraysize: illegal scope\n");
- script->reportdata(data);
- script_pushnil(st);
- st->state = END;
- return false;// not supported
- }
-
- script_pushint(st, script->getarraysize(st, reference_getid(data), reference_getindex(data), is_string_variable(name), reference_getref(data)));
+ script_pushint(st, script->array_highest_key(st,st->rid ? script->rid2sd(st) : NULL,reference_getname(data)));
return true;
}
+int script_array_index_cmp(const void *a, const void *b) {
+ return ( *(unsigned int*)a - *(unsigned int*)b );
+}
/// Deletes count or all the elements in an array, from the starting index.
/// ex: deletearray arr[4],2;
@@ -5569,10 +5745,12 @@ BUILDIN(deletearray)
{
struct script_data* data;
const char* name;
- int start;
- int end;
+ unsigned int start, end, i;
int id;
TBL_PC *sd = NULL;
+ struct script_array *sa = NULL;
+ struct DBMap *src = NULL;
+ void *value;
data = script_getdata(st, 2);
if( !data_isreference(data) )
@@ -5586,13 +5764,6 @@ BUILDIN(deletearray)
id = reference_getid(data);
start = reference_getindex(data);
name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:deletearray: illegal scope\n");
- script->reportdata(data);
- st->state = END;
- return false;// not supported
- }
if( not_server_variable(*name) )
{
@@ -5601,39 +5772,81 @@ BUILDIN(deletearray)
return true;// no player attached
}
- end = SCRIPT_MAX_ARRAYSIZE;
+ if( !(src = script->array_src(st,sd,name) ) ) {
+ ShowError("script:deletearray: not a array\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;// not a variable
+ } else if ( !(sa = idb_get(src, id)) ) { /* non-existent array, nothing to empty */
+ ShowError("script:deletearray: unknown array\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;// not a variable
+ }
+ end = script->array_highest_key(st,sd,name);
+
if( start >= end )
return true;// nothing to free
- if( script_hasdata(st,3) )
- {
- int count = script_getnum(st, 3);
+ if( is_string_variable(name) )
+ value = (void *)"";
+ else
+ value = (void *)0;
+
+ if( script_hasdata(st,3) ) {
+ unsigned int count = script_getnum(st, 3);
if( count > end - start )
count = end - start;
if( count <= 0 )
return true;// nothing to free
- // move rest of the elements backward
- for( ; start + count < end; ++start )
- {
- void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data));
- script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
- script_removetop(st, -1, 0);
+ if( end - start < sa->size ) {
+ // Better to iterate directly on the array, no speed-up from using sa
+ for( ; start + count < end; ++start ) {
+ // Compact and overwrite
+ void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data));
+ script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
+ script_removetop(st, -1, 0);
+ }
+ for( ; start < end; start++ ) {
+ // Clean up any leftovers that weren't overwritten
+ script->set_reg(st, sd, reference_uid(id, start), name, value, reference_getref(data));
+ }
+ } else {
+ // using sa to speed up
+ unsigned int *list = NULL, size = 0;
+ list = script->array_cpy_list(sa);
+ size = sa->size;
+ qsort(list, size, sizeof(unsigned int), script_array_index_cmp);
+
+ ARR_FIND(0, size, i, list[i] >= start);
+
+ for( ; i < size && list[i] < start + count; i++ ) {
+ // Clear any entries between start and start+count, if they exist
+ script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data));
+ }
+
+ for( ; i < size && list[i] < end; i++ ) {
+ // Move back count positions any entries between start+count to fill the gaps
+ void* v = script->get_val2(st, reference_uid(id, list[i]), reference_getref(data));
+ script->set_reg(st, sd, reference_uid(id, list[i]-count), name, v, reference_getref(data));
+ script_removetop(st, -1, 0);
+ // Clear their originals
+ script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data));
+ }
+ }
+ } else {
+ unsigned int *list = NULL, size = 0;
+ list = script->array_cpy_list(sa);
+ size = sa->size;
+
+ for(i = 0; i < size; i++) {
+ if( list[i] >= start ) // Less expensive than sorting it, most likely
+ script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data));
}
}
- // clear the rest of the array
- if( is_string_variable(name) )
- {
- for( ; start < end; ++start )
- script->set_reg(st, sd, reference_uid(id, start), name, (void *)"", reference_getref(data));
- }
- else
- {
- for( ; start < end; ++start )
- script->set_reg(st, sd, reference_uid(id, start), name, (void*)0, reference_getref(data));
- }
return true;
}
@@ -5646,7 +5859,7 @@ BUILDIN(getelementofarray)
struct script_data* data;
const char* name;
int32 id;
- int i;
+ int64 i;
data = script_getdata(st, 2);
if( !data_isreference(data) )
@@ -5659,27 +5872,18 @@ BUILDIN(getelementofarray)
}
id = reference_getid(data);
- name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:getelementofarray: illegal scope\n");
- script->reportdata(data);
- script_pushnil(st);
- st->state = END;
- return false;// not supported
- }
i = script_getnum(st, 3);
if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE )
{
- ShowWarning("script:getelementofarray: index out of range (%d)\n", i);
+ ShowWarning("script:getelementofarray: index out of range (%lld)\n", i);
script->reportdata(data);
script_pushnil(st);
st->state = END;
return false;// out of range
}
- script->push_val(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
+ script->push_val(st->stack, C_NAME, reference_uid(id, (unsigned int)i), reference_getref(data));
return true;
}
@@ -5976,19 +6180,13 @@ BUILDIN(checkweight2)
name_it = reference_getname(data_it);
name_nb = reference_getname(data_nb);
- if( not_array_variable(*name_it) || not_array_variable(*name_nb))
- {
- ShowError("script:checkweight2: illegal scope\n");
- script_pushint(st,0);
- return false;// not supported
- }
if(is_string_variable(name_it) || is_string_variable(name_nb)) {
ShowError("script:checkweight2: illegal type, need int\n");
script_pushint(st,0);
return false;// not supported
}
- nb_it = script->getarraysize(st, id_it, idx_it, 0, reference_getref(data_it));
- nb_nb = script->getarraysize(st, id_nb, idx_nb, 0, reference_getref(data_nb));
+ nb_it = script->array_highest_key(st,sd,reference_getname(data_it));
+ nb_nb = script->array_highest_key(st,sd,reference_getname(data_nb));
if(nb_it != nb_nb) {
ShowError("Size mistmatch: nb_it=%d, nb_nb=%d\n",nb_it,nb_nb);
fail = 1;
@@ -12810,7 +13008,7 @@ BUILDIN(getmapxy)
struct block_list *bl = NULL;
TBL_PC *sd=NULL;
- int num;
+ int64 num;
const char *name;
char prefix;
@@ -12910,7 +13108,7 @@ BUILDIN(getmapxy)
//Set MapName$
num=st->stack->stack_data[st->start+2].u.num;
- name=script->get_str(num&0x00ffffff);
+ name=script->get_str(script_getvarid(num));
prefix=*name;
if(not_server_variable(prefix))
@@ -12921,7 +13119,7 @@ BUILDIN(getmapxy)
//Set MapX
num=st->stack->stack_data[st->start+3].u.num;
- name=script->get_str(num&0x00ffffff);
+ name=script->get_str(script_getvarid(num));
prefix=*name;
if(not_server_variable(prefix))
@@ -12932,7 +13130,7 @@ BUILDIN(getmapxy)
//Set MapY
num=st->stack->stack_data[st->start+4].u.num;
- name=script->get_str(num&0x00ffffff);
+ name=script->get_str(script_getvarid(num));
prefix=*name;
if(not_server_variable(prefix))
@@ -13537,14 +13735,6 @@ BUILDIN(explode)
start = reference_getindex(data);
name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:explode: illegal scope\n");
- script->reportdata(data);
- st->state = END;
- return false;// not supported
- }
-
if( !is_string_variable(name) )
{
ShowError("script:explode: not string array\n");
@@ -13586,7 +13776,7 @@ BUILDIN(implode)
{
struct script_data* data = script_getdata(st, 2);
const char *glue = NULL, *name, *temp;
- int32 array_size, id;
+ uint32 array_size, id;
size_t len = 0, glue_len = 0, k = 0;
int i;
@@ -13605,14 +13795,6 @@ BUILDIN(implode)
id = reference_getid(data);
name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:implode: illegal scope\n");
- script->reportdata(data);
- st->state = END;
- return false;// not supported
- }
-
if( !is_string_variable(name) )
{
ShowError("script:implode: not string array\n");
@@ -13629,7 +13811,7 @@ BUILDIN(implode)
}
//count chars
- array_size = script->getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data)) - 1;
+ array_size = script->array_highest_key(st,sd,name) - 1;
if(array_size == -1) {
//empty array check (AmsTaff)
@@ -14270,8 +14452,6 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle)
return false;
}
}
- if( not_array_variable(*name) )
- max_rows = 1;// not an array, limit to one row
} else {
ShowError("script:query_sql: not a variable\n");
script->reportdata(data);
@@ -14857,13 +15037,6 @@ BUILDIN(searchitem)
id = reference_getid(data);
start = reference_getindex(data);
name = reference_getname(data);
- if( not_array_variable(*name) )
- {
- ShowError("script:searchitem: illegal scope\n");
- script->reportdata(data);
- st->state = END;
- return false;// not supported
- }
if( not_server_variable(*name) )
{
@@ -18811,11 +18984,11 @@ void script_defaults(void) {
script->next_id = 0;
script->st_ers = NULL;
script->stack_ers = NULL;
-
+ script->array_ers = NULL;
+
script->hq = NULL;
script->hqi = NULL;
script->hqs = script->hqis = 0;
- memset(&script->hqe, 0, sizeof(script->hqe));
script->buildin = NULL;
script->buildin_count = 0;
@@ -18868,6 +19041,9 @@ void script_defaults(void) {
script->potion_flag = script->potion_hp = script->potion_per_hp =
script->potion_sp = script->potion_per_sp = script->potion_target = 0;
+ script->generic_ui_array = NULL;
+ script->generic_ui_array_size = 0;
+ /* */
script->init = do_init_script;
script->final = do_final_script;
script->reload = script_reload;
@@ -18955,7 +19131,6 @@ void script_defaults(void) {
script->set_reg = set_reg;
script->stack_expand = stack_expand;
script->push_retinfo = push_retinfo;
- script->pop_val = pop_val;
script->op_3 = op_3;
script->op_2str = op_2str;
script->op_2num = op_2num;
@@ -18968,7 +19143,6 @@ void script_defaults(void) {
script->menu_countoptions = menu_countoptions;
script->buildin_areawarp_sub = buildin_areawarp_sub;
script->buildin_areapercentheal_sub = buildin_areapercentheal_sub;
- script->getarraysize = getarraysize;
script->buildin_delitem_delete = buildin_delitem_delete;
script->buildin_delitem_search = buildin_delitem_search;
script->buildin_killmonster_sub_strip = buildin_killmonster_sub_strip;
@@ -19033,4 +19207,23 @@ void script_defaults(void) {
script->global_casecheck.str_pos = 0;
memset(script->global_casecheck.str_hash, 0, sizeof(script->global_casecheck.str_hash));
// end ENABLE_CASE_CHECK
+
+ /**
+ * Array Handling
+ **/
+ script->array_src = script_array_src;
+ script->array_update = script_array_update;
+ script->array_add_member = script_array_add_member;
+ script->array_remove_member = script_array_remove_member;
+ script->array_delete = script_array_delete;
+ script->array_size = script_array_size;
+ script->array_free_db = script_free_array_db;
+ script->array_highest_key = script_array_highest_key;
+ /* */
+ script->reg_destroy_single = script_reg_destroy_single;
+ script->reg_destroy = script_reg_destroy;
+ /* */
+ script->generic_ui_array_expand = script_generic_ui_array_expand;
+ script->array_cpy_list = script_array_cpy_list;
+
}
diff --git a/src/map/script.h b/src/map/script.h
index 2f7499569..65e11d3ca 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -6,6 +6,7 @@
#define _SCRIPT_H_
#include "../common/strlib.h" //StringBuf
+#include "../common/cbasetypes.h"
#include "map.h" //EVENT_NAME_LENGTH
#include <setjmp.h>
@@ -28,8 +29,8 @@ struct eri;
#define NUM_WHISPER_VAR 10
-/// Maximum amount of elements in script arrays (soon getting ducked)
-#define SCRIPT_MAX_ARRAYSIZE 128
+/// Maximum amount of elements in script arrays
+#define SCRIPT_MAX_ARRAYSIZE (UINT_MAX - 1)
#define SCRIPT_BLOCK_SIZE 512
@@ -127,9 +128,9 @@ struct eri;
/// Returns the unique id of the reference (id and index)
#define reference_getuid(data) ( (data)->u.num )
/// Returns the id of the reference
-#define reference_getid(data) ( (int32)(reference_getuid(data) & 0x00ffffff) )
+#define reference_getid(data) ( (int32)(int64)(reference_getuid(data) & 0xFFFFFFFF) )
/// Returns the array index of the reference
-#define reference_getindex(data) ( (int32)(((uint32)(reference_getuid(data) & 0xff000000)) >> 24) )
+#define reference_getindex(data) ( (uint32)(int64)((reference_getuid(data) >> 32) & 0xFFFFFFFF) )
/// Returns the name of the reference
#define reference_getname(data) ( script->str_buf + script->str_data[reference_getid(data)].str )
/// Returns the linked list of uid-value pairs of the reference (can be NULL)
@@ -140,10 +141,12 @@ struct eri;
#define reference_getparamtype(data) ( script->str_data[reference_getid(data)].val )
/// Composes the uid of a reference from the id and the index
-#define reference_uid(id,idx) ( (int32)((((uint32)(id)) & 0x00ffffff) | (((uint32)(idx)) << 24)) )
+#define reference_uid(id,idx) ( (int64) ((uint64)(id) & 0xFFFFFFFF) | ((uint64)(idx) << 32) )
+
+#define script_getvarid(var) ( (int32)(int64)(var & 0xFFFFFFFF) )
+#define script_getvaridx(var) ( (uint32)(int64)((var >> 32) & 0xFFFFFFFF) )
#define not_server_variable(prefix) ( (prefix) != '$' && (prefix) != '.' && (prefix) != '\'')
-#define not_array_variable(prefix) ( (prefix) != '$' && (prefix) != '@' && (prefix) != '.' && (prefix) != '\'' )
#define is_string_variable(name) ( (name)[strlen(name) - 1] == '$' )
#define BUILDIN(x) bool buildin_ ## x (struct script_state* st)
@@ -339,7 +342,7 @@ struct script_retinfo {
struct script_data {
enum c_op type;
union script_data_val {
- int num;
+ int64 num;
char *str;
struct script_retinfo* ri;
} u;
@@ -350,8 +353,9 @@ struct script_data {
// it must be saved when script state is RERUNLINE. [Eoe / jA 1094]
struct script_code {
int script_size;
- unsigned char* script_buf;
- struct DBMap* script_vars;
+ unsigned char *script_buf;
+ struct DBMap *script_vars;
+ struct DBMap *script_arrays_db;
};
struct script_stack {
@@ -359,7 +363,8 @@ struct script_stack {
int sp_max;// capacity of the stack
int defsp;
struct script_data *stack_data;// stack
- struct DBMap* var_function;// scope variables
+ struct DBMap *var_function;// scope variables
+ struct DBMap *array_function_db;
};
/* [Ind/Hercules] */
@@ -401,13 +406,14 @@ struct script_state {
unsigned int id;
};
+/* TODO: HELLO DUCK THIS */
struct script_reg {
- int index;
+ int64 index;
int data;
};
-
+/* TODO: HELLO DUCK THIS */
struct script_regstr {
- int index;
+ int64 index;
char* data;
};
@@ -458,6 +464,12 @@ struct casecheck_data {
void (*clear) (void);
};
+struct script_array {
+ unsigned int id;/* the first 32b of the 64b uid, aka the id */
+ unsigned int size;/* how many members */
+ unsigned int *members;/* member list */
+};
+
/**
* Interface
**/
@@ -472,10 +484,13 @@ struct script_interface {
struct hQueue *hq;
struct hQueueIterator *hqi;
int hqs, hqis;
- int hqe[HQO_MAX];
/* */
char **buildin;
unsigned int buildin_count;
+ /**
+ * used to generate quick script_array entries
+ **/
+ struct eri *array_ers;
/* */
struct str_data_struct *str_data;
int str_data_size; // size of the data
@@ -531,6 +546,9 @@ struct script_interface {
int potion_flag; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex]
int potion_hp, potion_per_hp, potion_sp, potion_per_sp;
int potion_target;
+ /* */
+ unsigned int *generic_ui_array;
+ unsigned int generic_ui_array_size;
/* */
void (*init) (bool minimal);
void (*final) (void);
@@ -549,9 +567,9 @@ struct script_interface {
const char* (*conv_str) (struct script_state *st,struct script_data *data);
TBL_PC *(*rid2sd) (struct script_state *st);
void (*detach_rid) (struct script_state* st);
- struct script_data* (*push_val)(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref);
+ struct script_data* (*push_val)(struct script_stack* stack, enum c_op type, int64 val, struct DBMap** ref);
struct script_data *(*get_val) (struct script_state* st, struct script_data* data);
- void* (*get_val2) (struct script_state* st, int uid, struct DBMap** ref);
+ void* (*get_val2) (struct script_state* st, int64 uid, struct DBMap** ref);
struct script_data* (*push_str) (struct script_stack* stack, enum c_op type, char* str);
struct script_data* (*push_copy) (struct script_stack* stack, int pos);
void (*pop_stack) (struct script_state* st, int start, int end);
@@ -571,7 +589,7 @@ struct script_interface {
void (*free_state) (struct script_state* st);
void (*run_autobonus) (const char *autobonus,int id, int pos);
void (*cleararray_pc) (struct map_session_data* sd, const char* varname, void* value);
- void (*setarray_pc) (struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache);
+ void (*setarray_pc) (struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache);
int (*config_read) (char *cfgName);
int (*add_str) (const char* p);
const char* (*get_str) (int id);
@@ -615,10 +633,9 @@ struct script_interface {
void (*read_constdb) (void);
const char* (*print_line) (StringBuf *buf, const char *p, const char *mark, int line);
void (*errorwarning_sub) (StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos);
- int (*set_reg) (struct script_state *st, TBL_PC *sd, int num, const char *name, const void *value, struct DBMap **ref);
+ int (*set_reg) (struct script_state *st, TBL_PC *sd, int64 num, const char *name, const void *value, struct DBMap **ref);
void (*stack_expand) (struct script_stack *stack);
struct script_data* (*push_retinfo) (struct script_stack *stack, struct script_retinfo *ri, DBMap **ref);
- int (*pop_val) (struct script_state *st);
void (*op_3) (struct script_state *st, int op);
void (*op_2str) (struct script_state *st, int op, const char *s1, const char *s2);
void (*op_2num) (struct script_state *st, int op, int i1, int i2);
@@ -631,7 +648,6 @@ struct script_interface {
int (*menu_countoptions) (const char *str, int max_count, int *total);
int (*buildin_areawarp_sub) (struct block_list *bl, va_list ap);
int (*buildin_areapercentheal_sub) (struct block_list *bl, va_list ap);
- int32 (*getarraysize) (struct script_state *st, int32 id, int32 idx, int isstring, struct DBMap **ref);
void (*buildin_delitem_delete) (struct map_session_data *sd, int idx, int *amount, bool delete_items);
bool (*buildin_delitem_search) (struct map_session_data *sd, struct item *it, bool exact_match);
int (*buildin_killmonster_sub_strip) (struct block_list *bl, va_list ap);
@@ -661,6 +677,23 @@ struct script_interface {
struct casecheck_data local_casecheck;
struct casecheck_data global_casecheck;
// end ENABLE_CASE_CHECK
+ /**
+ * Array Handling
+ **/
+ struct DBMap *(*array_src) (struct script_state *st, struct map_session_data *sd, const char *name);
+ void (*array_update) (struct DBMap **src, int64 num, bool empty);
+ void (*array_delete) (struct DBMap *src, struct script_array *sa);
+ void (*array_remove_member) (struct DBMap *src, struct script_array *sa, unsigned int idx);
+ void (*array_add_member) (struct script_array *sa, unsigned int idx);
+ unsigned int (*array_size) (struct script_state *st, struct map_session_data *sd, const char *name);
+ unsigned int (*array_highest_key) (struct script_state *st, struct map_session_data *sd, const char *name);
+ int (*array_free_db) (DBKey key, DBData *data, va_list ap);
+ /* */
+ void (*reg_destroy_single) (struct map_session_data *sd, int64 reg, struct script_reg_state *data);
+ int (*reg_destroy) (DBKey key, DBData *data, va_list ap);
+ /* */
+ void (*generic_ui_array_expand) (unsigned int plus);
+ unsigned int *(*array_cpy_list) (struct script_array *sa);
};
struct script_interface *script;
diff --git a/src/map/skill.c b/src/map/skill.c
index 28937048e..0804adf90 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -2539,8 +2539,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
}
tsd->reproduceskill_id = copy_skill;
- pc_setglobalreg(tsd, "REPRODUCE_SKILL", copy_skill);
- pc_setglobalreg(tsd, "REPRODUCE_SKILL_LV", lv);
+ pc_setglobalreg(tsd, script->add_str("REPRODUCE_SKILL"), copy_skill);
+ pc_setglobalreg(tsd, script->add_str("REPRODUCE_SKILL_LV"), lv);
tsd->status.skill[cidx].id = copy_skill;
tsd->status.skill[cidx].lv = lv;
@@ -2562,8 +2562,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
lv = type;
tsd->cloneskill_id = copy_skill;
- pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill);
- pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv);
+ pc_setglobalreg(tsd, script->add_str("CLONE_SKILL"), copy_skill);
+ pc_setglobalreg(tsd, script->add_str("CLONE_SKILL_LV"), lv);
tsd->status.skill[cidx].id = copy_skill;
tsd->status.skill[cidx].lv = lv;
@@ -5660,7 +5660,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
sd->mission_mobid = id;
sd->mission_count = 0;
- pc_setglobalreg(sd,"TK_MISSION_ID", id);
+ pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), id);
clif->mission_info(sd, id, 0);
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
}
@@ -7414,7 +7414,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if (skill_id == SL_SUPERNOVICE && dstsd && dstsd->die_counter && !(rnd()%100))
{ //Erase death count 1% of the casts
dstsd->die_counter = 0;
- pc_setglobalreg(dstsd,"PC_DIE_COUNTER", 0);
+ pc_setglobalreg(dstsd,script->add_str("PC_DIE_COUNTER"), 0);
clif->specialeffect(bl, 0x152, AREA);
//SC_SOULLINK invokes status_calc_pc for us.
}
@@ -16597,7 +16597,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid,
{ //Cooking items.
clif->specialeffect(&sd->bl, 608, AREA);
if( sd->cook_mastery < 1999 )
- pc_setglobalreg(sd, "COOK_MASTERY",sd->cook_mastery + ( 1 << ( (skill->produce_db[idx].itemlv - 11) / 2 ) ) * 5);
+ pc_setglobalreg(sd, script->add_str("COOK_MASTERY"),sd->cook_mastery + ( 1 << ( (skill->produce_db[idx].itemlv - 11) / 2 ) ) * 5);
}
break;
}
@@ -16698,7 +16698,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid,
{ //Cooking items.
clif->specialeffect(&sd->bl, 609, AREA);
if( sd->cook_mastery > 0 )
- pc_setglobalreg(sd, "COOK_MASTERY", sd->cook_mastery - ( 1 << ((skill->produce_db[idx].itemlv - 11) / 2) ) - ( ( ( 1 << ((skill->produce_db[idx].itemlv - 11) / 2) ) >> 1 ) * 3 ));
+ pc_setglobalreg(sd, script->add_str("COOK_MASTERY"), sd->cook_mastery - ( 1 << ((skill->produce_db[idx].itemlv - 11) / 2) ) - ( ( ( 1 << ((skill->produce_db[idx].itemlv - 11) / 2) ) >> 1 ) * 3 ));
}
}
}
diff --git a/src/map/trade.c b/src/map/trade.c
index 6f079bdd3..44b669ebd 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -178,7 +178,7 @@ int impossible_trade_check(struct map_session_data *sd)
nullpo_retr(1, sd);
if(sd->deal.zeny > sd->status.zeny) {
- pc_setglobalreg(sd,"ZENY_HACKER",1);
+ pc_setglobalreg(sd,script->add_str("ZENY_HACKER"),1);
return -1;
}
diff --git a/src/map/unit.c b/src/map/unit.c
index 7f722684d..d801a72f0 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2352,20 +2352,13 @@ int unit_free(struct block_list *bl, clr_type clrtype) {
pc->delspiritball(sd,sd->spiritball,1);
for(i = 1; i < 5; i++)
pc->del_charm(sd, sd->charm[i], i);
-
- if( sd->reg ) { //Double logout already freed pointer fix... [Skotlex]
- aFree(sd->reg);
- sd->reg = NULL;
- sd->reg_num = 0;
- }
- if( sd->regstr ) {
- for( i = 0; i < sd->regstr_num; ++i )
- if( sd->regstr[i].data )
- aFree(sd->regstr[i].data);
- aFree(sd->regstr);
- sd->regstr = NULL;
- sd->regstr_num = 0;
- }
+
+ if( sd->var_db )
+ sd->var_db->destroy(sd->var_db,script->reg_destroy);
+
+ if( sd->array_db )
+ sd->array_db->destroy(sd->array_db,script->array_free_db);
+
if( sd->st && sd->st->state != RUN ) {// free attached scripts that are waiting
script->free_state(sd->st);
sd->st = NULL;