summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt6
-rw-r--r--conf-tmpl/inter_athena.conf4
-rw-r--r--db/packet_db.txt2
-rw-r--r--sql-files/main.sql15
-rw-r--r--sql-files/upgrade_svn11018.sql10
-rw-r--r--src/char/char.c82
-rw-r--r--src/char_sql/char.c49
-rw-r--r--src/common/mmo.h16
-rw-r--r--src/map/atcommand.h2
-rw-r--r--src/map/clif.c37
-rw-r--r--src/map/clif.h1
-rw-r--r--src/map/party.c2
12 files changed, 219 insertions, 7 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 585d673ed..77bc25e8e 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -4,6 +4,12 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2007/08/15
+ * Merged and completed Latio's work on server-side hot-key saving
+ (http://www.eathena.ws/board/index.php?s=&showtopic=159388&view=findpost&p=884453):
+ Now hotkeys are stored server-side (table hotkey in SQL servers, file
+ save/hotkeys.txt for TXT servers). You can disable this behaviour by
+ commenting out the 'HOTKEY_SAVING' define in mmo.h
+ * Apply upgrade_svn11018.sql to create the hotkey table. [Skotlex]
* Some serious code cleanups
- adjusted @reloadbattleconf to not depend on variable ordering
- changed all battle vars to 'int' (removes pointless duplicit coding)
diff --git a/conf-tmpl/inter_athena.conf b/conf-tmpl/inter_athena.conf
index 29a14461a..29bdb7aa2 100644
--- a/conf-tmpl/inter_athena.conf
+++ b/conf-tmpl/inter_athena.conf
@@ -8,6 +8,9 @@ storage_txt: save/storage.txt
// Party flatfile database, for party names, members and other party info.
party_txt: save/party.txt
+// Hotkeys flatfile database, where character skill shortcuts are stored.
+hotkeys_txt: save/hotkeys.txt
+
// Guild flatfile database, for guild names, members, and other guild info.
guild_txt: save/guild.txt
@@ -114,6 +117,7 @@ loginlog_db: loginlog
// Character Database Tables
char_db: char
+hotkey_db: hotkey
scdata_db: sc_data
cart_db: cart_inventory
inventory_db: inventory
diff --git a/db/packet_db.txt b/db/packet_db.txt
index 7bcba9b61..9a06f6806 100644
--- a/db/packet_db.txt
+++ b/db/packet_db.txt
@@ -1014,7 +1014,7 @@ packet_ver: 22
0x02b7,10
0x02b8,22
0x02b9,191
-0x02ba,11
+0x02ba,11,hotkey,2:4:5:9
0x02bb,8
0x02bc,6
diff --git a/sql-files/main.sql b/sql-files/main.sql
index d77b8fb42..cae4570b2 100644
--- a/sql-files/main.sql
+++ b/sql-files/main.sql
@@ -117,6 +117,21 @@ CREATE TABLE `friends` (
) TYPE=MyISAM;
--
+-- Table structure for table `hotkey`
+--
+
+DROP TABLE IF EXISTS `hotkey`;
+CREATE TABLE `hotkey` (
+ `char_id` INT(11) NOT NULL,
+ `hotkey` TINYINT(2) unsigned NOT NULL,
+ `type` TINYINT(1) unsigned NOT NULL default '0',
+ `itemskill_id` INT(11) unsigned NOT NULL default '0',
+ `skill_lvl` TINYINT(4) unsigned NOT NULL default '0',
+ PRIMARY KEY (`char_id`,`hotkey`),
+ INDEX (`char_id`)
+) TYPE=MYISAM;
+
+--
-- Table structure for table `global_reg_value`
--
diff --git a/sql-files/upgrade_svn11018.sql b/sql-files/upgrade_svn11018.sql
new file mode 100644
index 000000000..176d7e12d
--- /dev/null
+++ b/sql-files/upgrade_svn11018.sql
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS `hotkey`;
+CREATE TABLE `hotkey` (
+ `char_id` INT(11) NOT NULL,
+ `hotkey` TINYINT(2) unsigned NOT NULL,
+ `type` TINYINT(1) unsigned NOT NULL default '0',
+ `itemskill_id` INT(11) unsigned NOT NULL default '0',
+ `skill_lvl` TINYINT(4) unsigned NOT NULL default '0',
+ PRIMARY KEY (`char_id`,`hotkey`),
+ INDEX (`char_id`)
+) TYPE=MYISAM;
diff --git a/src/char/char.c b/src/char/char.c
index 7d39e6d92..2ae559f20 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -46,6 +46,7 @@
char char_txt[1024] = "save/athena.txt";
char friends_txt[1024] = "save/friends.txt";
+char hotkeys_txt[1024] = "save/hotkeys.txt";
char char_log_filename[1024] = "log/char.log";
int save_log = 1; // show loading/saving messages
@@ -445,6 +446,22 @@ int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p)
return 0;
}
+/*---------------------------------------------------
+ Make a data line for hotkeys list
+ --------------------------------------------------*/
+int mmo_hotkeys_tostr(char *str, struct mmo_charstatus *p)
+{
+ int i;
+ char *str_p = str;
+ str_p += sprintf(str_p, "%d", p->char_id);
+#ifdef HOTKEY_SAVING
+ for (i=0;i<HOTKEY_SAVING;i++)
+ str_p += sprintf(str_p, ",%d,%d,%d", p->hotkeys[i].type, p->hotkeys[i].id, p->hotkeys[i].lv);
+#endif
+ str_p += '\0';
+
+ return 0;
+}
//-------------------------------------------------
// Function to create the character line (for save)
//-------------------------------------------------
@@ -891,6 +908,53 @@ int parse_friend_txt(struct mmo_charstatus *p)
return count;
}
+//---------------------------------
+// Function to read hotkey list
+//---------------------------------
+int parse_hotkey_txt(struct mmo_charstatus *p)
+{
+#ifdef HOTKEY_SAVING
+ char line[1024];
+ int pos = 0, count = 0, next;
+ int i,len;
+ int type, id, lv;
+ FILE *fp;
+
+ // Open the file and look for the ID
+ fp = fopen(hotkeys_txt, "r");
+ if(fp == NULL)
+ return -1;
+
+ while(fgets(line, sizeof(line), fp))
+ {
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+ if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id)
+ continue; //Not this line...
+ //Read hotkeys
+ len = strlen(line);
+ next = pos;
+ for (count = 0; next < len && count < HOTKEY_SAVING; count++)
+ {
+ if (sscanf(line+next, ",%d,%d,%d%n",&type,&id,&lv, &pos) < 3)
+ //Invalid entry?
+ break;
+ p->hotkeys[count].type = type;
+ p->hotkeys[count].id = id;
+ p->hotkeys[count].lv = lv;
+ next+=pos;
+ }
+ break; //Found hotkeys.
+ }
+ fclose(fp);
+ return count;
+#else
+ return 0;
+#endif
+}
+
+
+
#ifndef TXT_SQL_CONVERT
//---------------------------------
// Function to read characters file
@@ -944,7 +1008,9 @@ int mmo_char_init(void)
// Initialize friends list
parse_friend_txt(&char_dat[char_num].status); // Grab friends for the character
-
+ // Initialize hotkey list
+ parse_hotkey_txt(&char_dat[char_num].status); // Grab hotkeys for the character
+
if (ret > 0) { // negative value or zero for errors
if (char_dat[char_num].status.char_id >= char_id_count)
char_id_count = char_dat[char_num].status.char_id + 1;
@@ -1049,7 +1115,17 @@ void mmo_char_sync(void)
lock_fclose(f_fp, friends_txt, &lock);
- //aFree(id);
+#ifdef HOTKEY_SAVING
+ // Hotkey List data save (Skotlex)
+ f_fp = lock_fopen(hotkeys_txt, &lock);
+ for(i = 0; i < char_num; i++) {
+ mmo_hotkeys_tostr(f_line, &char_dat[id[i]].status);
+ fprintf(f_fp, "%s" RETCODE, f_line);
+ }
+
+ lock_fclose(f_fp, hotkeys_txt, &lock);
+#endif
+
DELETE_BUFFER(id);
return;
@@ -4059,6 +4135,8 @@ int char_config_read(const char *cfgName)
strcpy(char_txt, w2);
} else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw
strcpy(friends_txt, w2);
+ } else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw
+ strcpy(hotkeys_txt, w2);
#ifndef TXT_SQL_CONVERT
} else if (strcmpi(w1, "max_connect_user") == 0) {
max_connect_user = atoi(w2);
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index d3081df57..5ff26c0aa 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -57,6 +57,7 @@ char guild_storage_db[256] = "guild_storage";
char party_db[256] = "party";
char pet_db[256] = "pet";
char friend_db[256] = "friends";
+char hotkey_db[256] = "hotkey";
#ifndef TXT_SQL_CONVERT
static struct dbt *char_db_;
@@ -731,7 +732,28 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus *p){
strcat(save_status, " friends");
}
-
+#ifdef HOTKEY_SAVING
+ // hotkeys
+ tmp_ptr = tmp_sql;
+ tmp_ptr += sprintf(tmp_ptr, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db);
+ diff = 0;
+ for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){
+ if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey)))
+ {
+ tmp_ptr += sprintf(tmp_ptr, "('%d','%d','%d','%d','%d'),", char_id, i, p->hotkeys[i].type, p->hotkeys[i].id , p->hotkeys[i].lv);
+ diff = 1;
+ }
+ }
+ if(diff) {
+ tmp_ptr[-1] = 0;
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else {
+ strcat(save_status, " hotkeys");
+ }
+ }
+#endif
if (save_status[0]!='\0' && save_log)
ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status);
#ifndef TXT_SQL_CONVERT
@@ -1083,6 +1105,29 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
strcat (t_msg, " friends");
}
+#ifdef HOTKEY_SAVING
+ //Hotkeys
+ sprintf(tmp_sql, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=%d ORDER BY `hotkey` LIMIT %d;", hotkey_db, char_id, HOTKEY_SAVING);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n", mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__, __LINE__, tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res) {
+ while ((sql_row = mysql_fetch_row(sql_res))) {
+ n = atoi(sql_row[0]);
+ if( n < 0 || n >= HOTKEY_SAVING)
+ continue;
+ p->hotkeys[n].type = atoi(sql_row[1]);
+ p->hotkeys[n].id = atoi(sql_row[2]);
+ p->hotkeys[n].lv = atoi(sql_row[3]);
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " hotkeys");
+ }
+#endif
+
if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
cp = idb_ensure(char_db_, char_id, create_charstatus);
@@ -3765,6 +3810,8 @@ void sql_config_read(const char* cfgName)
strcpy(pet_db,w2);
else if(!strcmpi(w1,"friend_db"))
strcpy(friend_db,w2);
+ else if(!strcmpi(w1,"hotkey_db"))
+ strcpy(hotkey_db,w2);
#ifndef TXT_SQL_CONVERT
else if(!strcmpi(w1,"db_path"))
strcpy(db_path,w2);
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 2a42c017c..0fcfff137 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -13,6 +13,11 @@
//Remove/Comment this line to disable sc_data saving. [Skotlex]
#define ENABLE_SC_SAVING
+//Remove/Comment this line to disable server-side hot-key saving support [Skotlex]
+//Note that newer clients no longer save hotkeys in the registry!
+//The number is the max number of hotkeys to save (27 = 9 skills x 3 bars)
+#define HOTKEY_SAVING 27
+
#define MAX_MAP_PER_SERVER 1024
#define MAX_INVENTORY 100
//Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
@@ -180,6 +185,14 @@ struct friend {
char name[NAME_LENGTH];
};
+#ifdef HOTKEY_SAVING
+struct hotkey {
+ unsigned int id;
+ unsigned short lv;
+ unsigned char type; // 0: item, 1: skill
+};
+#endif
+
struct mmo_charstatus {
int char_id;
int account_id;
@@ -217,6 +230,9 @@ struct mmo_charstatus {
struct skill skill[MAX_SKILL];
struct friend friends[MAX_FRIENDS]; //New friend system [Skotlex]
+#ifdef HOTKEY_SAVING
+ struct hotkey hotkeys[HOTKEY_SAVING];
+#endif
};
struct registry {
diff --git a/src/map/atcommand.h b/src/map/atcommand.h
index 7f76dbf30..a4fd609d2 100644
--- a/src/map/atcommand.h
+++ b/src/map/atcommand.h
@@ -10,6 +10,8 @@
//Note: The range is unlimited unless this define is set.
//#define AUTOLOOT_DISTANCE AREA_SIZE
+#include "map.h"
+
enum AtCommandType {
AtCommand_None = -1,
AtCommand_Broadcast = 0,
diff --git a/src/map/clif.c b/src/map/clif.c
index 30646a5b3..335d94ccf 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -8083,6 +8083,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
clif_updatestatus(sd,SP_NEXTJOBEXP);
clif_updatestatus(sd,SP_SKILLPOINT);
clif_initialstatus(sd);
+ clif_hotkeys_send(sd);
if (sd->sc.option&OPTION_FALCON)
clif_status_load(&sd->bl, SI_FALCON, 1);
@@ -8193,6 +8194,38 @@ void clif_parse_TickSend(int fd, struct map_session_data *sd)
return;
}
+void clif_hotkeys_send(struct map_session_data *sd) {
+#ifdef HOTKEY_SAVING
+ const int fd = sd->fd;
+ int i;
+ if (!fd) return;
+ WFIFOHEAD(fd, 2+HOTKEY_SAVING*7);
+ WFIFOW(fd, 0) = 0x02b9;
+ for(i = 0; i < HOTKEY_SAVING; i++) {
+ WFIFOB(fd, 2 + 0 + i * 7) = sd->status.hotkeys[i].type; // type: 0: item, 1: skill
+ WFIFOL(fd, 2 + 1 + i * 7) = sd->status.hotkeys[i].id; // item or skill ID
+ WFIFOW(fd, 2 + 5 + i * 7) = sd->status.hotkeys[i].lv; // skill level
+ }
+ WFIFOSET(fd, packet_len(0x02b9));
+#endif
+}
+
+void clif_parse_Hotkey(int fd, struct map_session_data *sd) {
+#ifdef HOTKEY_SAVING
+ unsigned short idx;
+ int cmd;
+
+ cmd = RFIFOW(fd, 0);
+ idx = RFIFOW(fd, packet_db[sd->packet_ver][cmd].pos[0]);
+ if (idx >= HOTKEY_SAVING) return;
+
+ sd->status.hotkeys[idx].type = RFIFOB(fd, packet_db[sd->packet_ver][cmd].pos[1]);
+ sd->status.hotkeys[idx].id = RFIFOL(fd, packet_db[sd->packet_ver][cmd].pos[2]);
+ sd->status.hotkeys[idx].lv = RFIFOW(fd, packet_db[sd->packet_ver][cmd].pos[3]);
+ return;
+#endif
+}
+
/*==========================================
*
*------------------------------------------*/
@@ -11705,7 +11738,7 @@ static int packetdb_readdb(void)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,191, 0, 0, 0, 0, 0, 0,
//#0x02C0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -11843,13 +11876,13 @@ static int packetdb_readdb(void)
{clif_parse_FeelSaveOk,"feelsaveok"},
{clif_parse_AdoptRequest,"adopt"},
{clif_parse_debug,"debug"},
- //[blackhole89] //[orn]
{clif_parse_ChangeHomunculusName,"changehomunculusname"},
{clif_parse_HomMoveToMaster,"hommovetomaster"},
{clif_parse_HomMoveTo,"hommoveto"},
{clif_parse_HomAttack,"homattack"},
{clif_parse_HomMenu,"hommenu"},
{clif_parse_StoragePassword,"storagepassword"},
+ {clif_parse_Hotkey,"hotkey"},
{NULL,NULL}
};
diff --git a/src/map/clif.h b/src/map/clif.h
index 458dfd281..bb510b94a 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -144,6 +144,7 @@ void clif_soundeffect(struct map_session_data* sd, struct block_list* bl, const
int clif_soundeffectall(struct block_list* bl, const char *name, int type, enum send_target coverage);
void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick);
void clif_parse_LoadEndAck(int fd,struct map_session_data *sd);
+void clif_hotkeys_send(struct map_session_data *sd);
// trade
int clif_traderequest(struct map_session_data* sd, const char* name);
diff --git a/src/map/party.c b/src/map/party.c
index 2427dab98..195e844cb 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -712,7 +712,7 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b
// count the number of players eligible for exp sharing
for (i = c = 0; i < MAX_PARTY; i++) {
if( (sd[c] = p->data[i].sd) == NULL || sd[c]->bl.m != src->m || pc_isdead(sd[c]) ||
- battle_config.idle_no_share && (sd[c]->chatID || sd[c]->vender_id || sd[c]->idletime < last_tick - battle_config.idle_no_share) )
+ (battle_config.idle_no_share && (sd[c]->chatID || sd[c]->vender_id || sd[c]->idletime < last_tick - battle_config.idle_no_share)) )
continue;
c++;
}