Follow up Autotrade Persistency, also as fix of bugreport:8572 http://rathena.org/board/tracker/issue-8572-vendingc/

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>
This commit is contained in:
Cydh Ramdh 2014-02-02 12:44:52 +07:00
parent 007b88f2bb
commit 46ca940692
3 changed files with 160 additions and 126 deletions

View File

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

View File

@ -564,7 +564,7 @@ void chrif_on_ready(void) {
//Re-save any guild castles that were modified in the disconnection time. //Re-save any guild castles that were modified in the disconnection time.
guild_castle_reconnect(-1, 0, 0); guild_castle_reconnect(-1, 0, 0);
// Charserver is ready for this now // Charserver is ready for laoding autotrader
do_init_vending_autotrade(); do_init_vending_autotrade();
} }

View File

@ -23,30 +23,36 @@
#include <stdlib.h> // atoi #include <stdlib.h> // atoi
#include <string.h> #include <string.h>
struct vending_entry{ /// Struct for vending entry of autotrader
struct s_autotrade_entry {
int cartinventory_id; int cartinventory_id;
int amount; uint16 amount;
int price; int price;
int index; uint16 index;
}; };
struct vending{ /// Struct of autotrader
struct s_autotrade {
int account_id; int account_id;
int char_id; int char_id;
int vendor_id; int vendor_id;
int m; int m;
int x; uint16 x,
int y; y;
unsigned char sex; unsigned char sex;
char title[MESSAGE_SIZE]; char title[MESSAGE_SIZE];
uint32 count; uint16 count;
struct vending_entry** entries; struct s_autotrade_entry **entries;
struct map_session_data *sd; struct map_session_data *sd;
}; };
static int vending_nextid = 0; ///Vending_id counter static int vending_nextid = 0; ///Vending_id counter
static DBMap *vending_db; ///Db holder the vender : charid -> map_session_data static DBMap *vending_db; ///Db holder the vender : charid -> map_session_data
static DBMap *autotrade_db;
//Autotrader
static struct s_autotrade **autotraders; ///Autotraders Storage
static uint16 autotrader_count; ///Autotrader count
static void do_final_vending_autotrade(void);
/** /**
* Lookup to get the vending_db outside module * Lookup to get the vending_db outside module
@ -453,40 +459,42 @@ bool vending_searchall(struct map_session_data* sd, const struct s_search_store_
return true; return true;
} }
/** Open vending for Autotrader
* @param sd Player as autotrader
*/
void vending_reopen( struct map_session_data* sd ){ void vending_reopen( struct map_session_data* sd ){
int i, count; if (!sd || !autotrader_count || !autotraders)
uint8 *data, *p;
uint16 *index, *amount;
uint32 *value;
struct vending *vending;
struct vending_entry *entry;
vending = (struct vending*)idb_get( autotrade_db, sd->status.char_id );
if( !vending ){
map_quit(sd);
return; return;
} else { // Ready to open vending for this char
uint16 i;
uint8 *data, *p;
uint16 j, count;
if( vending->count > 0 ){ ARR_FIND(0,autotrader_count,i,autotraders[i] && autotraders[i]->char_id == sd->status.char_id);
data = (uint8*)aMalloc( vending->count * 8 ); if (i >= autotrader_count) { //This is shouldn't happen [Cydh]
ShowError("vending_reopen: Player not found as autotrader (aid:%d cid:%d)\n",sd->status.account_id,sd->status.char_id);
return;
}
for( i = 0, p = data, count = vending->count; i < vending->count; i++ ){ // Init vending data for autotrader
entry = vending->entries[i]; CREATE(data, uint8, autotraders[i]->count * 8);
index = (uint16*)(p + 0); for (j = 0, p = data, count = autotraders[i]->count; j < autotraders[i]->count; j++) {
amount = (uint16*)(p + 2); struct s_autotrade_entry *entry = autotraders[i]->entries[j];
value = (uint32*)(p + 4); uint16 *index = (uint16*)(p + 0);
uint16 *amount = (uint16*)(p + 2);
uint32 *value = (uint32*)(p + 4);
ARR_FIND( 0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id ); // Find item position in cart
ARR_FIND(0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id);
if( entry->index == MAX_CART ){ if (entry->index == MAX_CART) {
count--; count--;
continue; continue;
} }
*index = entry->index + 2; *index = entry->index + 2;
*amount = entry->amount; *amount = min(entry->amount, sd->status.cart[entry->index].amount); // Limit the vending amount
*value = entry->price; *value = entry->price;
p += 8; p += 8;
@ -496,154 +504,180 @@ void vending_reopen( struct map_session_data* sd ){
sd->state.prevend = 1; sd->state.prevend = 1;
// Open the shop again // Open the shop again
vending_openvending( sd, vending->title, data, count ); vending_openvending(sd, autotraders[i]->title, data, count);
aFree(data);
ShowInfo("Autotrader loaded: '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n",
sd->status.name,count,mapindex_id2name(sd->mapindex),sd->bl.x,sd->bl.y);
// Set him to autotrade // Set him to autotrade
if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ){ if (Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;",
vendings_db, sd->vender_id ) != SQL_SUCCESS )
{
Sql_ShowDebug( mmysql_handle ); Sql_ShowDebug( mmysql_handle );
} }
// Make him look perfect // Make him look perfect
unit_setdir(&sd->bl,battle_config.feature_autotrade_direction); unit_setdir(&sd->bl,battle_config.feature_autotrade_direction);
if( battle_config.feature_autotrade_sit ){ if( battle_config.feature_autotrade_sit )
pc_setsit(sd); pc_setsit(sd);
}
}
aFree(data); //If the last autotrade is loaded, clear autotraders [Cydh]
if (i+1 >= autotrader_count)
idb_remove( autotrade_db, sd->status.char_id ); do_final_vending_autotrade();
for( i = 0; i < vending->count; i++ ){
aFree( vending->entries[i] );
}
aFree(vending->entries);
aFree(vending);
if( !count ){
map_quit(sd);
} }
} }
void do_init_vending_autotrade( void ){ /**
if( battle_config.feature_autotrade ){ * Initializing autotraders from table
struct vending **autotraders; */
struct vending *vending; void do_init_vending_autotrade( void ) {
struct vending_entry *entry; if (battle_config.feature_autotrade) {
uint32 count; uint16 i, items = 0;
int i, j; autotrader_count = 0;
if( Sql_Query(mmysql_handle, // Get autotrader from table. `map`, `x`, and `y`, aren't used here
"SELECT `id`, `account_id`, `char_id`, `sex`, `map`, `x`, `y`, `title`" // Just read player that has data at vending_items [Cydh]
"FROM `%s`" if (Sql_Query(mmysql_handle,
"WHERE `autotrade` = 1;", vendings_db ) != SQL_SUCCESS ) { "SELECT `id`, `account_id`, `char_id`, `sex`, `title` "
"FROM `%s` "
"WHERE `autotrade` = 1 AND (SELECT COUNT(`vending_id`) FROM `%s` WHERE `vending_id` = `id`) > 0;",
vendings_db, vending_items_db ) != SQL_SUCCESS )
{
Sql_ShowDebug(mmysql_handle); Sql_ShowDebug(mmysql_handle);
return; return;
} }
count = (uint32)Sql_NumRows(mmysql_handle); if (!(autotrader_count = (uint32)Sql_NumRows(mmysql_handle))) //Nothing to do
if( count <= 0 ){
return; return;
}
autotraders = (struct vending**)aMalloc( sizeof( struct vending* ) * count ); // Init autotraders
CREATE(autotraders, struct s_autotrade *, autotrader_count);
// Init each autotrader data
i = 0; i = 0;
while (SQL_SUCCESS == Sql_NextRow(mmysql_handle) && i < autotrader_count) {
while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) {
size_t len; size_t len;
char* data; char* data;
vending = autotraders[i] = (struct vending *)aMalloc( sizeof( struct vending ) ); CREATE(autotraders[i], struct s_autotrade, 1);
Sql_GetData( mmysql_handle, 0, &data, NULL ); vending->vendor_id = atoi(data); Sql_GetData(mmysql_handle, 0, &data, NULL); autotraders[i]->vendor_id = atoi(data);
Sql_GetData( mmysql_handle, 1, &data, NULL ); vending->account_id = atoi(data); Sql_GetData(mmysql_handle, 1, &data, NULL); autotraders[i]->account_id = atoi(data);
Sql_GetData( mmysql_handle, 2, &data, NULL ); vending->char_id = atoi(data); Sql_GetData(mmysql_handle, 2, &data, NULL); autotraders[i]->char_id = atoi(data);
Sql_GetData( mmysql_handle, 3, &data, NULL ); vending->sex = data[0]; Sql_GetData(mmysql_handle, 3, &data, NULL); autotraders[i]->sex = (data[0] == 'F') ? 0 : 1;
Sql_GetData( mmysql_handle, 4, &data, NULL ); vending->m = map_mapname2mapid( data ); Sql_GetData(mmysql_handle, 4, &data, &len); safestrncpy(autotraders[i]->title, data, min(len + 1, MESSAGE_SIZE));
Sql_GetData( mmysql_handle, 5, &data, NULL ); vending->x = atoi(data); autotraders[i]->count = 0;
Sql_GetData( mmysql_handle, 6, &data, NULL ); vending->y = atoi(data);
Sql_GetData( mmysql_handle, 7, &data, &len ); safestrncpy( vending->title, data, min( len + 1, MESSAGE_SIZE ) );
vending->count = 0;
idb_put( autotrade_db, vending->char_id, vending );
// initialize player // initialize player
CREATE(vending->sd, TBL_PC, 1); CREATE(autotraders[i]->sd, struct map_session_data, 1);
pc_setnewpc( vending->sd, vending->account_id, vending->char_id, 0, gettick(), vending->sex == 'F' ? 0 : 1, 0 ); pc_setnewpc(autotraders[i]->sd, autotraders[i]->account_id, autotraders[i]->char_id, 0, gettick(), autotraders[i]->sex, 0);
vending->sd->state.autotrade = 1;
chrif_authreq( vending->sd, true );
autotraders[i]->sd->state.autotrade = 1;
chrif_authreq(autotraders[i]->sd, true);
i++; i++;
} }
Sql_FreeResult(mmysql_handle);
Sql_FreeResult( mmysql_handle ); if (autotraders == NULL) { //This is shouldn't happen [Cydh]
ShowError("Failed to initialize autotraders!\n");
do_final_vending_autotrade();
return;
}
for( i = 0; i < count; i++ ){ //Init items on vending list each autotrader
vending = autotraders[i]; for (i = 0; i < autotrader_count; i++){
struct s_autotrade *at = NULL;
uint16 j;
if( SQL_ERROR == Sql_Query(mmysql_handle, if (autotraders[i] == NULL)
"SELECT `cartinventory_id`, `amount`, `price`" continue;
"FROM `%s`" at = autotraders[i];
if (SQL_ERROR == Sql_Query(mmysql_handle,
"SELECT `cartinventory_id`, `amount`, `price` "
"FROM `%s` "
"WHERE `vending_id` = %d " "WHERE `vending_id` = %d "
"ORDER BY `index` ASC;", vending_items_db, vending->vendor_id ) ) { "ORDER BY `index` ASC;", vending_items_db, at->vendor_id ) )
{
Sql_ShowDebug(mmysql_handle); Sql_ShowDebug(mmysql_handle);
continue; continue;
} }
vending->count = (uint32)Sql_NumRows(mmysql_handle); if (!(at->count = (uint32)Sql_NumRows(mmysql_handle))) {
map_quit(at->sd);
if( vending->count <= 0 ){
// Player was not correctly deleted, must not be set online
idb_remove( autotrade_db, vending->char_id );
map_quit(vending->sd);
aFree(vending);
continue; continue;
} }
vending->entries = (struct vending_entry**)aMalloc( sizeof( struct vending_entry* ) * vending->count ); //Init the list
CREATE(at->entries, struct s_autotrade_entry *,at->count);
//Add the item into list
j = 0; j = 0;
while (SQL_SUCCESS == Sql_NextRow(mmysql_handle) && j < at->count) {
while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) {
char* data; char* data;
CREATE(at->entries[j], struct s_autotrade_entry, 1);
entry = vending->entries[j] = (struct vending_entry*)aMalloc( sizeof( struct vending_entry ) ); Sql_GetData(mmysql_handle, 0, &data, NULL); at->entries[j]->cartinventory_id = atoi(data);
Sql_GetData(mmysql_handle, 1, &data, NULL); at->entries[j]->amount = atoi(data);
Sql_GetData( mmysql_handle, 0, &data, NULL ); entry->cartinventory_id = atoi(data); Sql_GetData(mmysql_handle, 2, &data, NULL); at->entries[j]->price = atoi(data);
Sql_GetData( mmysql_handle, 1, &data, NULL ); entry->amount = atoi(data);
Sql_GetData( mmysql_handle, 2, &data, NULL ); entry->price = atoi(data);
j++; j++;
} }
items += j;
Sql_FreeResult( mmysql_handle ); Sql_FreeResult(mmysql_handle);
} }
aFree(autotraders); ShowStatus("Done loading '"CL_WHITE"%d"CL_RESET"' autotraders with '"CL_WHITE"%d"CL_RESET"' items.\n", autotrader_count, items);
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' autotraders.\n",count);
} }
// Everything is loaded fine, their entries will be reinserted once they are loaded // Everything is loaded fine, their entries will be reinserted once they are loaded
if( Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vendings_db ) != SQL_SUCCESS || if (Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vendings_db ) != SQL_SUCCESS ||
Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vending_items_db ) != SQL_SUCCESS ){ Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vending_items_db ) != SQL_SUCCESS)
{
Sql_ShowDebug(mmysql_handle); Sql_ShowDebug(mmysql_handle);
} }
} }
/**
* Clear all autotraders
* @author [Cydh]
*/
void do_final_vending_autotrade(void) {
if (!autotrader_count || !autotraders)
return;
else {
uint16 i = 0;
while (i < autotrader_count) { //Free the autotrader
if (autotraders[i] == NULL)
continue;
if (autotraders[i]->count) {
uint16 j = 0;
while (j < autotraders[i]->count) { //Free the autotrade entries
if (autotraders[i]->entries == NULL)
continue;
if (autotraders[i]->entries[j])
aFree(autotraders[i]->entries[j]);
j++;
}
aFree(autotraders[i]->entries);
}
aFree(autotraders[i]);
i++;
}
aFree(autotraders);
autotrader_count = 0;
}
}
/** /**
* Initialise the vending module * Initialise the vending module
* called in map::do_init * called in map::do_init
*/ */
void do_final_vending(void) { void do_final_vending(void) {
db_destroy(vending_db); db_destroy(vending_db);
db_destroy(autotrade_db); do_final_vending_autotrade(); //Make sure everything is cleared [Cydh]
} }
/** /**
@ -652,6 +686,5 @@ void do_final_vending(void) {
*/ */
void do_init_vending(void) { void do_init_vending(void) {
vending_db = idb_alloc(DB_OPT_BASE); vending_db = idb_alloc(DB_OPT_BASE);
autotrade_db = idb_alloc(DB_OPT_BASE);
vending_nextid = 0; vending_nextid = 0;
} }