Skip to content
Permalink
Browse files
Merge pull request #40 from Lemongrass3110/master
Added autotrade persistence support.
- Players who are autotrading during a crash/shut down will be restored on start up.
- Live vendor data is stored in SQL.
- Credits to Ind and Lemongrass.
  • Loading branch information
aleos89 committed Jan 23, 2014
2 parents 80f7984 + 3f1242e commit 27cbc7ff24fc896f5b2346ee01fad16864f559ad
@@ -22,3 +22,15 @@ feature.atcommand_suggestions: off
// Banking (Note 1)
// Requires: 2013-07-24aRagexe or later
feature.banking: on

// Autotrade persistency (Note 1)
// Should vendors that used @autotrade be restored after a restart?
feature.autotrade: on

// In which direction should respawned autotraders look?
// Possible values are from 0-7
// Default: 4(South)
feature.autotrade_direction: 4

// Do you want your autotraders to sit? (Note 1)
feature.autotrade_sit: yes
@@ -122,6 +122,8 @@ mob_skill_db_re_db: mob_skill_db_re
mob_skill_db2_db: mob_skill_db2
//mob_skill_db2_db: mob_skill_db2_re
mapreg_db: mapreg
vending_db: vendings
vending_items_db: vending_items

// Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no)
use_sql_db: no
@@ -12014,7 +12014,7 @@ OnTouch:

que_job01,6,94,0 warp morocc#01 2,2,morocc,45,103
que_job01,17,48,0 warp que_job01#02 2,2,que_job01,68,92
que_job01,68,96,0 warp que_job01#03 2,2,que_job01,17,53;
que_job01,68,96,0 warp que_job01#03 2,2,que_job01,17,53

que_job01,82,95,3 script Bar Master#moc2_01 46,{
if (checkweight(1201,1) == 0) {
@@ -2548,7 +2548,7 @@ OnTouch:
}
}

spl_in02,236,86,0 warp terrashome_out 1,1,splendide,285,139;
spl_in02,236,86,0 warp terrashome_out 1,1,splendide,285,139

spl_fild01,357,44,0 script ???#ep13mdf01 844,{
if (checkweight(1201,2) == 0) {
@@ -2409,9 +2409,9 @@ lou_in02,192,170,0 script Supply Stack#2 111,{
close;
}

louyang,129,121,0 warp Storage Warp#1 1,1,lou_in02,203,161;
louyang,125,121,0 warp Storage Warp#2 1,1,lou_in02,198,161;
lou_in02,198,159,0 warp Storage Warp#3 1,1,louyang,124,118;
louyang,129,121,0 warp Storage Warp#1 1,1,lou_in02,203,161
louyang,125,121,0 warp Storage Warp#2 1,1,lou_in02,198,161
lou_in02,198,159,0 warp Storage Warp#3 1,1,louyang,124,118
lou_in02,203,159,0 warp Storage Warp#4 1,1,louyang,129,118

// Poison King Quest :: poison_king
@@ -3646,8 +3646,8 @@ que_ba,181,14,7 script Researcher#bpast_2_2 865,{
close;
}

que_ba,183,25,0 warp #bpast_2to3_1 1,1,que_ba,72,25;
que_ba,183,52,0 warp #bpast_2to3_2 1,1,que_ba,72,51;
que_ba,183,25,0 warp #bpast_2to3_1 1,1,que_ba,72,25
que_ba,183,52,0 warp #bpast_2to3_2 1,1,que_ba,72,51

que_ba,102,56,0 script #3room_barmunt -1,3,3,{
//OnTouch2:
@@ -712,3 +712,24 @@ CREATE TABLE IF NOT EXISTS `bonus_script` (
`type` char(1) NOT NULL DEFAULT '0',
`icon` varchar(3) NOT NULL DEFAULT '-1'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `vending_items` (
`vending_id` int(10) unsigned NOT NULL,
`index` smallint(5) unsigned NOT NULL,
`cartinventory_id` int(10) unsigned NOT NULL,
`amount` smallint(5) unsigned NOT NULL,
`price` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `vendings` (
`id` int(10) unsigned NOT NULL,
`account_id` int(11) unsigned NOT NULL,
`char_id` int(10) unsigned NOT NULL,
`sex` enum('F','M') NOT NULL DEFAULT 'M',
`map` varchar(20) NOT NULL,
`x` smallint(5) unsigned NOT NULL,
`y` smallint(5) unsigned NOT NULL,
`title` varchar(80) NOT NULL,
`autotrade` tinyint(4) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
@@ -0,0 +1,20 @@
CREATE TABLE IF NOT EXISTS `vending_items` (
`vending_id` int(10) unsigned NOT NULL,
`index` smallint(5) unsigned NOT NULL,
`cartinventory_id` int(10) unsigned NOT NULL,
`amount` smallint(5) unsigned NOT NULL,
`price` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `vendings` (
`id` int(10) unsigned NOT NULL,
`account_id` int(11) unsigned NOT NULL,
`char_id` int(10) unsigned NOT NULL,
`sex` enum('F','M') NOT NULL DEFAULT 'M',
`map` varchar(20) NOT NULL,
`x` smallint(5) unsigned NOT NULL,
`y` smallint(5) unsigned NOT NULL,
`title` varchar(80) NOT NULL,
`autotrade` tinyint(4) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
@@ -3308,10 +3308,6 @@ int parse_frommap(int fd)
WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
WFIFOW(fd,12) = count;
WFIFOSET(fd,WFIFOW(fd,2));

//Clear the data once loaded.
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
Sql_ShowDebug(sql_handle);
}
}
Sql_FreeResult(sql_handle);
@@ -3715,8 +3711,10 @@ int parse_frommap(int fd)
cid = RFIFOL(fd, 8);
count = RFIFOW(fd, 12);

if( count > 0 )
{
// Whatever comes from the mapserver, now is the time to drop previous entries
if( Sql_Query( sql_handle, "DELETE FROM `%s` where `account_id` = %d and `char_id` = %d;", scdata_db, aid, cid ) != SQL_SUCCESS ){
Sql_ShowDebug( sql_handle );
}else if( count > 0 ){
struct status_change_data data;
StringBuf buf;
int i;
@@ -3779,7 +3777,7 @@ int parse_frommap(int fd)
break;

case 0x2b26: // auth request from map-server
if (RFIFOREST(fd) < 19)
if (RFIFOREST(fd) < 20)
return 0;

{
@@ -3791,13 +3789,15 @@ int parse_frommap(int fd)
struct auth_node* node;
struct mmo_charstatus* cd;
struct mmo_charstatus char_dat;
bool autotrade = false;

account_id = RFIFOL(fd,2);
char_id = RFIFOL(fd,6);
login_id1 = RFIFOL(fd,10);
sex = RFIFOB(fd,14);
ip = ntohl(RFIFOL(fd,15));
RFIFOSKIP(fd,19);
autotrade = RFIFOB(fd,19);
RFIFOSKIP(fd,20);

node = (struct auth_node*)idb_get(auth_db, account_id);
cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
@@ -3806,7 +3806,25 @@ int parse_frommap(int fd)
mmo_char_fromsql(char_id, &char_dat, true);
cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
}
if( runflag == CHARSERVER_ST_RUNNING &&

if( runflag == CHARSERVER_ST_RUNNING && autotrade && cd ){
uint32 mmo_charstatus_len = sizeof(struct mmo_charstatus) + 25;
cd->sex = sex;

WFIFOHEAD(fd,mmo_charstatus_len);
WFIFOW(fd,0) = 0x2afd;
WFIFOW(fd,2) = mmo_charstatus_len;
WFIFOL(fd,4) = account_id;
WFIFOL(fd,8) = 0;
WFIFOL(fd,12) = 0;
WFIFOL(fd,16) = 0;
WFIFOL(fd,20) = 0;
WFIFOB(fd,24) = 0;
memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
WFIFOSET(fd, WFIFOW(fd,2));

set_char_online(id, char_id, account_id);
}else if( runflag == CHARSERVER_ST_RUNNING &&
cd != NULL &&
node != NULL &&
node->account_id == account_id &&
@@ -5653,13 +5653,22 @@ ACMD_FUNC(autotrade) {
}

sd->state.autotrade = 1;

if( battle_config.feature_autotrade &&
sd->state.vending &&
Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", "vendings", sd->vender_id ) != SQL_SUCCESS ){
Sql_ShowDebug( mmysql_handle );
}

if( battle_config.at_timeout ) {
int timeout = atoi(message);
status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0);
}

channel_pcquit(sd,0xF); //leave all chan
clif_authfail_fd(sd->fd, 15);

chrif_save(sd,3);

return 0;
}
@@ -7340,6 +7340,9 @@ static const struct _battle_data {
{ "discount_item_point_shop", &battle_config.discount_item_point_shop, 0, 0, 3, },
{ "update_enemy_position", &battle_config.update_enemy_position, 0, 0, 1, },
{ "devotion_rdamage", &battle_config.devotion_rdamage, 0, 0, 100, },
{ "feature.autotrade", &battle_config.feature_autotrade, 1, 0, 1, },
{ "feature.autotrade_direction", &battle_config.feature_autotrade_direction, 4, 0, 7, },
{ "feature.autotrade_sit", &battle_config.feature_autotrade_sit, 1, 0, 1, },
};
#ifndef STATS_OPT_OUT
/**
@@ -520,6 +520,11 @@ extern struct Battle_Config
int discount_item_point_shop;
int update_enemy_position;
int devotion_rdamage;

// autotrade persistency
int feature_autotrade;
int feature_autotrade_direction;
int feature_autotrade_sit;
} battle_config;

void do_init_battle(void);
@@ -119,6 +119,8 @@ int channel_delete(struct Channel *channel) {
int channel_join(struct Channel *channel, struct map_session_data *sd) {
if(!channel || !sd)
return -1;
if(sd->state.autotrade)
return 0; // fake success
if(channel_haspc(channel,sd)==1)
return -2;

@@ -277,6 +277,7 @@ int chrif_isconnected(void) {
* Saves character data.
* Flag = 1: Character is quitting
* Flag = 2: Character is changing map-servers
* Flag = 3: Character used @autotrade
*------------------------------------------*/
int chrif_save(struct map_session_data *sd, int flag) {
uint32 mmo_charstatus_len = 0;
@@ -292,7 +293,7 @@ int chrif_save(struct map_session_data *sd, int flag) {
chrif_save_bsdata(sd);
chrif_req_login_operation(sd->status.account_id, sd->status.name, 7, 0, 2, sd->status.bank_vault); //save Bank data
}
if ( !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) )
if ( flag != 3 && !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) )
ShowError("chrif_save: Failed to set up player %d:%d for proper quitting!\n", sd->status.account_id, sd->status.char_id);
}

@@ -562,6 +563,9 @@ void chrif_on_ready(void) {

//Re-save any guild castles that were modified in the disconnection time.
guild_castle_reconnect(-1, 0, 0);

// Charserver is ready for this now
do_init_vending_autotrade();
}


@@ -615,22 +619,23 @@ int chrif_skillcooldown_request(int account_id, int char_id) {
/*==========================================
* Request auth confirmation
*------------------------------------------*/
void chrif_authreq(struct map_session_data *sd) {
void chrif_authreq(struct map_session_data *sd, bool autotrade) {
struct auth_node *node= chrif_search(sd->bl.id);

if( node != NULL || !chrif_isconnected() ) {
set_eof(sd->fd);
return;
}

WFIFOHEAD(char_fd,19);
WFIFOHEAD(char_fd,20);
WFIFOW(char_fd,0) = 0x2b26;
WFIFOL(char_fd,2) = sd->status.account_id;
WFIFOL(char_fd,6) = sd->status.char_id;
WFIFOL(char_fd,10) = sd->login_id1;
WFIFOB(char_fd,14) = sd->status.sex;
WFIFOL(char_fd,15) = htonl(session[sd->fd]->client_addr);
WFIFOSET(char_fd,19);
WFIFOB(char_fd,19) = autotrade;
WFIFOSET(char_fd,20);
chrif_sd_to_auth(sd, ST_LOGIN);
}

@@ -1117,8 +1122,13 @@ int chrif_disconnectplayer(int fd) {
}

if (!sd->fd) { //No connection
if (sd->state.autotrade)
if (sd->state.autotrade){
if( sd->state.vending ){
vending_closevending(sd);
}

map_quit(sd); //Remove it.
}
//Else we don't remove it because the char should have a timer to remove the player because it force-quit before,
//and we don't want them kicking their previous instance before the 10 secs penalty time passes. [Skotlex]
return 0;
@@ -1286,9 +1296,6 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the
count++;
}

if (count == 0)
return 0; //Nothing to save.

WFIFOW(char_fd,12) = count;
WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size
WFIFOSET(char_fd,WFIFOW(char_fd,2));
@@ -1364,6 +1371,11 @@ int chrif_load_scdata(int fd) {
status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 1|2|4|8);
}
#endif

if( sd->state.autotrade ){
vending_reopen( sd );
}

return 0;
}

@@ -35,7 +35,7 @@ struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state st
bool chrif_auth_delete(int account_id, int char_id, enum sd_state state);
bool chrif_auth_finished(struct map_session_data* sd);

void chrif_authreq(struct map_session_data* sd);
void chrif_authreq(struct map_session_data* sd, bool autotrade);
void chrif_authok(int fd);
int chrif_scdata_request(int account_id, int char_id);
int chrif_skillcooldown_request(int account_id, int char_id);
@@ -9441,7 +9441,7 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd)
WFIFOSET(fd,packet_len(0x283));
#endif

chrif_authreq(sd);
chrif_authreq(sd,false);
}


@@ -17857,6 +17857,7 @@ void packetdb_readdb(void)
packet_len(i) = packet_len_table[i];

for(f = 0; f<ARRAYLENGTH(filename); f++){
entries = 0;
sprintf(line, "%s/%s", db_path,filename[f]);
if( (fp=fopen(line,"r"))==NULL ){
if(f==0) {
@@ -18004,7 +18005,8 @@ void packetdb_readdb(void)

clif_config.packet_db_ver = j?j:MAX_PACKET_VER;
}
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, "packet_db.txt");
sprintf(line, "%s/%s", db_path,filename[f]);
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, line);
}
ShowStatus("Using default packet version: "CL_WHITE"%d"CL_RESET".\n", clif_config.packet_db_ver);
}
@@ -2105,7 +2105,7 @@ void do_init_guild(void) {
for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
int n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
char* dbsubpath1 = aMalloc(n1+1);
safesnprintf(dbsubpath1,n1+1,"%s/%s",db_path,dbsubpath[i]);
safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);

sv_readdb(dbsubpath1, "castle_db.txt", ',', 4, 4, -1, &guild_read_castledb, i);
sv_readdb(dbsubpath1, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, &guild_read_guildskill_tree_db, i); //guild skill tree [Komurka]

2 comments on commit 27cbc7f

@euphyy
Copy link
Contributor

@euphyy euphyy commented on 27cbc7f Jan 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, @Lemongrass3110! ^^

@nanakiwurtz
Copy link
Contributor

@nanakiwurtz nanakiwurtz commented on 27cbc7f Jan 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice commit 🍰
What about the 'battle_config.at_timeout' check?
Will it be restarted upon server restart, or resume the timer?

Please sign in to comment.