/*========================================== * MYSQL_BINDにステートメント結果をセット *------------------------------------------ */ bool sqldbs_stmt_bind_column(struct sqldbs_stmt *st, size_t idx, int buffer_type, void *buffer, size_t buffer_length) { nullpo_retr(false, st); if(st->bind_columns == false) { size_t i, cols; // MYSQL_BINDの用意 cols = sqldbs_stmt_field_count(st); if(st->max_columns < cols) { st->max_columns = cols; st->columns = (MYSQL_BIND *)aRealloc(st->columns, sizeof(MYSQL_BIND) * cols); } memset(st->columns, 0, cols * sizeof(MYSQL_BIND)); for(i = 0; i < cols; i++) { st->columns[i].buffer_type = MYSQL_TYPE_NULL; } } if(idx >= st->max_columns) return false; sqldbs_stmt_bind_datatype(st->columns + idx, buffer_type, buffer, buffer_length, NULL, NULL); st->bind_columns = true; return true; }
/** * Load achievements for a character. * @param char_id: Character ID * @param count: Pointer to return the number of found entries. * @return Array of found entries. It has *count entries, and it is care of the caller to aFree() it afterwards. */ struct achievement *mapif_achievements_fromsql(uint32 char_id, int *count) { struct achievement *achievelog = NULL; struct achievement tmp_achieve; SqlStmt *stmt; StringBuf buf; int i; if (!count) return NULL; memset(&tmp_achieve, 0, sizeof(tmp_achieve)); StringBuf_Init(&buf); StringBuf_AppendStr(&buf, "SELECT `id`, COALESCE(UNIX_TIMESTAMP(`completed`),0), COALESCE(UNIX_TIMESTAMP(`rewarded`),0)"); for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; ++i) StringBuf_Printf(&buf, ", `count%d`", i + 1); StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id` = '%u'", schema_config.achievement_table, char_id); stmt = SqlStmt_Malloc(sql_handle); if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || SQL_ERROR == SqlStmt_Execute(stmt) ) { SqlStmt_ShowDebug(stmt); SqlStmt_Free(stmt); StringBuf_Destroy(&buf); *count = 0; return NULL; } SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_achieve.achievement_id, 0, NULL, NULL); SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_achieve.completed, 0, NULL, NULL); SqlStmt_BindColumn(stmt, 2, SQLDT_INT, &tmp_achieve.rewarded, 0, NULL, NULL); for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; ++i) SqlStmt_BindColumn(stmt, 3 + i, SQLDT_INT, &tmp_achieve.count[i], 0, NULL, NULL); *count = (int)SqlStmt_NumRows(stmt); if (*count > 0) { i = 0; achievelog = (struct achievement *)aCalloc(*count, sizeof(struct achievement)); while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { if (i >= *count) // Sanity check, should never happen break; memcpy(&achievelog[i++], &tmp_achieve, sizeof(tmp_achieve)); } if (i < *count) { // Should never happen. Compact array *count = i; achievelog = (struct achievement *)aRealloc(achievelog, sizeof(struct achievement) * i); } } SqlStmt_Free(stmt); StringBuf_Destroy(&buf); ShowInfo("achievement load complete from DB - id: %d (total: %d)\n", char_id, *count); return achievelog; }
int acquire_timer (void) { int i; if (free_timer_list_pos) { do { i = free_timer_list[--free_timer_list_pos]; } while(i >= timer_data_num && free_timer_list_pos > 0); } else i = timer_data_num; if (i >= timer_data_num) for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++); if (i >= timer_data_num && i >= timer_data_max) { if (timer_data_max == 0) { timer_data_max = 256; timer_data = (struct TimerData*) aCalloc( sizeof(struct TimerData) , timer_data_max); } else { timer_data_max += 256; timer_data = (struct TimerData *) aRealloc( timer_data, sizeof(struct TimerData) * timer_data_max); memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData) * 256); } } return i; }
/*====================================== * CORE : Timer Heap *-------------------------------------- */ static void push_timer_heap(int index) { int i, j; int min, max, pivot; // for sorting // check number of element if (timer_heap_num >= timer_heap_max) { if (timer_heap_max == 0) { timer_heap_max = 256; timer_heap = (int *) aCalloc( sizeof(int) , 256); } else { timer_heap_max += 256; timer_heap = (int *) aRealloc( timer_heap, sizeof(int) * timer_heap_max); memset(timer_heap + (timer_heap_max - 256), 0, sizeof(int) * 256); } } // do a sorting from higher to lower j = timer_data[index].tick; // speed up // with less than 4 values, it's speeder to use simple loop if (timer_heap_num < 4) { for(i = timer_heap_num; i > 0; i--) // if (j < timer_data[timer_heap[i - 1]].tick) //Plain comparisons break on bound looping timers. [Skotlex] if (DIFF_TICK(j, timer_data[timer_heap[i - 1]].tick) < 0) break; else timer_heap[i] = timer_heap[i - 1]; timer_heap[i] = index; // searching by dichotomie } else { // if lower actual item is higher than new // if (j < timer_data[timer_heap[timer_heap_num - 1]].tick) //Plain comparisons break on bound looping timers. [Skotlex] if (DIFF_TICK(j, timer_data[timer_heap[timer_heap_num - 1]].tick) < 0) timer_heap[timer_heap_num] = index; else { // searching position min = 0; max = timer_heap_num - 1; while (min < max) { pivot = (min + max) / 2; // if (j < timer_data[timer_heap[pivot]].tick) //Plain comparisons break on bound looping timers. [Skotlex] if (DIFF_TICK(j, timer_data[timer_heap[pivot]].tick) < 0) min = pivot + 1; else max = pivot; } // move elements - do loop if there are a little number of elements to move if (timer_heap_num - min < 5) { for(i = timer_heap_num; i > min; i--) timer_heap[i] = timer_heap[i - 1]; // move elements - else use memmove (speeder for a lot of elements) } else memmove(&timer_heap[min + 1], &timer_heap[min], sizeof(int) * (timer_heap_num - min)); // save new element timer_heap[min] = index; } } timer_heap_num++; }
int do_timer(unsigned int tick) { int i, nextmin = 1000; if (tick < 0x010000 && fix_heap_flag) { fix_timer_heap(tick); fix_heap_flag = 0; } while(timer_heap_num) { i = timer_heap[timer_heap_num - 1]; // next shorter element if ((nextmin = DIFF_TICK(timer_data[i].tick, tick)) > 0) break; if (timer_heap_num > 0) // suppress the actual element from the table timer_heap_num--; timer_data[i].type |= TIMER_REMOVE_HEAP; if (timer_data[i].func) { if (nextmin < -1000) { // 1秒以上の大幅な遅延が発生しているので、 // timer処理タイミングを現在値とする事で // 呼び出し時タイミング(引数のtick)相対で処理してる // timer関数の次回処理タイミングを遅らせる timer_data[i].func(i, tick, timer_data[i].id, timer_data[i].data); } else { timer_data[i].func(i, timer_data[i].tick, timer_data[i].id, timer_data[i].data); } } if (timer_data[i].type & TIMER_REMOVE_HEAP) { switch(timer_data[i].type & ~TIMER_REMOVE_HEAP) { case TIMER_ONCE_AUTODEL: timer_data[i].type = 0; if (free_timer_list_pos >= free_timer_list_max) { free_timer_list_max += 256; free_timer_list = (int *) aRealloc(free_timer_list, sizeof(int) * free_timer_list_max); memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); } free_timer_list[free_timer_list_pos++] = i; break; case TIMER_INTERVAL: if (DIFF_TICK(timer_data[i].tick , tick) < -1000) { timer_data[i].tick = tick + timer_data[i].interval; } else { timer_data[i].tick += timer_data[i].interval; } timer_data[i].type &= ~TIMER_REMOVE_HEAP; push_timer_heap(i); break; } } } if (nextmin < TIMER_MIN_INTERVAL) nextmin = TIMER_MIN_INTERVAL; if ((unsigned int)(tick + nextmin) < tick) //Tick will loop, rearrange the heap on the next iteration. fix_heap_flag = 1; return nextmin; }
/** * Loads the entire questlog for a character. * * @param char_id Character ID * @param count Pointer to return the number of found entries. * @return Array of found entries. It has *count entries, and it is care of the * caller to aFree() it afterwards. */ struct quest *mapif_quests_fromsql(int char_id, int *count) { struct quest *questlog = NULL; struct quest tmp_quest; SqlStmt *stmt; if (!count) return NULL; stmt = SQL->StmtMalloc(sql_handle); if (stmt == NULL) { SqlStmt_ShowDebug(stmt); *count = 0; return NULL; } memset(&tmp_quest, 0, sizeof(struct quest)); if (SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=?", quest_db) || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SQL->StmtExecute(stmt) || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); *count = 0; return NULL; } *count = (int)SQL->StmtNumRows(stmt); if (*count > 0) { int i = 0; questlog = (struct quest *)aCalloc(*count, sizeof(struct quest)); while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) { if (i >= *count) // Sanity check, should never happen break; memcpy(&questlog[i++], &tmp_quest, sizeof(tmp_quest)); } if (i < *count) { // Should never happen. Compact array *count = i; questlog = aRealloc(questlog, sizeof(struct quest)*i); } } SQL->StmtFree(stmt); return questlog; }
void searchstore_query(struct map_session_data* sd, unsigned char type, unsigned int min_price, unsigned int max_price, const unsigned short* itemlist, unsigned int item_count, const unsigned short* cardlist, unsigned int card_count) { unsigned int i; struct map_session_data* pl_sd; struct DBIterator *iter; struct s_search_store_search s; searchstore_searchall_t store_searchall; time_t querytime; DBMap *vending_db = vending_getdb(); if( !battle_config.feature_search_stores ) { return; } if( !sd->searchstore.open ) { return; } if( ( store_searchall = searchstore_getsearchallfunc(type) ) == NULL ) { ShowError("searchstore_query: Unknown search type %u (account_id=%d).\n", (unsigned int)type, sd->bl.id); return; } time(&querytime); if( sd->searchstore.nextquerytime > querytime ) { clif_search_store_info_failed(sd, SSI_FAILED_LIMIT_SEARCH_TIME); return; } if( !sd->searchstore.uses ) { clif_search_store_info_failed(sd, SSI_FAILED_SEARCH_CNT); return; } // validate lists for( i = 0; i < item_count; i++ ) { if( !itemdb_exists(itemlist[i]) ) { ShowWarning("searchstore_query: Client resolved item %hu is not known.\n", itemlist[i]); clif_search_store_info_failed(sd, SSI_FAILED_NOTHING_SEARCH_ITEM); return; } } for( i = 0; i < card_count; i++ ) { if( !itemdb_exists(cardlist[i]) ) { ShowWarning("searchstore_query: Client resolved card %hu is not known.\n", cardlist[i]); clif_search_store_info_failed(sd, SSI_FAILED_NOTHING_SEARCH_ITEM); return; } } if( max_price < min_price ) { swap(min_price, max_price); } sd->searchstore.uses--; sd->searchstore.type = type; sd->searchstore.nextquerytime = querytime+battle_config.searchstore_querydelay; // drop previous results searchstore_clear(sd); // allocate max. amount of results sd->searchstore.items = (struct s_search_store_info_item*)aMalloc(sizeof(struct s_search_store_info_item)*battle_config.searchstore_maxresults); // search s.search_sd = sd; s.itemlist = itemlist; s.cardlist = cardlist; s.item_count = item_count; s.card_count = card_count; s.min_price = min_price; s.max_price = max_price; iter = db_iterator(vending_db); for( pl_sd = dbi_first(iter); dbi_exists(iter); pl_sd = dbi_next(iter) ) { if( sd == pl_sd ) {// skip own shop, if any continue; } if( !store_searchall(pl_sd, &s) ) {// exceeded result size clif_search_store_info_failed(sd, SSI_FAILED_OVER_MAXCOUNT); break; } } dbi_destroy(iter); if( sd->searchstore.count ) { // reclaim unused memory sd->searchstore.items = (struct s_search_store_info_item*)aRealloc(sd->searchstore.items, sizeof(struct s_search_store_info_item)*sd->searchstore.count); // present results clif_search_store_info_ack(sd); // one page displayed sd->searchstore.pages++; } else { // cleanup searchstore_clear(sd); // update uses clif_search_store_info_ack(sd); // notify of failure clif_search_store_info_failed(sd, SSI_FAILED_NOTHING_SEARCH_ITEM); } }
/** * Loads the entire questlog for a character. * * @param char_id Character ID * @param count Pointer to return the number of found entries. * @return Array of found entries. It has *count entries, and it is care of the * caller to aFree() it afterwards. */ struct quest *mapif_quests_fromsql(int char_id, int *count) { struct quest *questlog = NULL; struct quest tmp_quest; SqlStmt *stmt; StringBuf buf; int i; int sqlerror = SQL_SUCCESS; if (!count) return NULL; stmt = SQL->StmtMalloc(sql_handle); if (stmt == NULL) { SqlStmt_ShowDebug(stmt); *count = 0; return NULL; } StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `quest_id`, `state`, `time`"); for (i = 0; i < MAX_QUEST_OBJECTIVES; i++) { StrBuf->Printf(&buf, ", `count%d`", i+1); } StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=?", quest_db); memset(&tmp_quest, 0, sizeof(struct quest)); if (SQL_ERROR == SQL->StmtPrepare(stmt, StrBuf->Value(&buf)) || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SQL->StmtExecute(stmt) || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) ) sqlerror = SQL_ERROR; StrBuf->Destroy(&buf); for (i = 0; sqlerror != SQL_ERROR && i < MAX_QUEST_OBJECTIVES; i++) { // Stop on the first error sqlerror = SQL->StmtBindColumn(stmt, 3+i, SQLDT_INT, &tmp_quest.count[i], 0, NULL, NULL); } if (sqlerror == SQL_ERROR) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); *count = 0; return NULL; } *count = (int)SQL->StmtNumRows(stmt); if (*count > 0) { i = 0; questlog = (struct quest *)aCalloc(*count, sizeof(struct quest)); while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) { if (i >= *count) // Sanity check, should never happen break; memcpy(&questlog[i++], &tmp_quest, sizeof(tmp_quest)); } if (i < *count) { // Should never happen. Compact array *count = i; questlog = aRealloc(questlog, sizeof(struct quest)*i); } } SQL->StmtFree(stmt); return questlog; }