GetTradeRecipe converted to QueryDatabase

This commit is contained in:
Arthur Ice 2014-10-08 15:43:50 -07:00
parent e2894ef2aa
commit 21d6865e8c

View File

@ -1149,194 +1149,167 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float
bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id, bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id,
uint32 char_id, DBTradeskillRecipe_Struct *spec) uint32 char_id, DBTradeskillRecipe_Struct *spec)
{ {
char errbuf[MYSQL_ERRMSG_SIZE];
MYSQL_RES *result;
MYSQL_ROW row;
char *query = 0;
char buf2[4096];
uint32 sum = 0; std::string containers;// make where clause segment for container(s)
uint32 count = 0; if (some_id == 0)
uint32 qcount = 0; containers = StringFormat("= %u", c_type); // world combiner so no item number
uint32 qlen = 0; else
containers = StringFormat("IN (%u,%u)", c_type, some_id); // container in inventory
// make where clause segment for container(s)
char containers[30];
if (some_id == 0) {
// world combiner so no item number
snprintf(containers,29, "= %u", c_type);
} else {
// container in inventory
snprintf(containers,29, "in (%u,%u)", c_type, some_id);
}
buf2[0] = '\0';
//Could prolly watch for stacks in this loop and handle them properly... //Could prolly watch for stacks in this loop and handle them properly...
//just increment sum and count accordingly //just increment sum and count accordingly
bool first = true; bool first = true;
uint8 i; std::string buf2;
char *pos = buf2; uint32 count = 0;
for (i = 0; i < 10; i++) { // <watch> TODO: need to determine if this is bound to world/item container size uint32 sum = 0;
for (uint8 i = 0; i < 10; i++) { // <watch> TODO: need to determine if this is bound to world/item container size
const ItemInst* inst = container->GetItem(i); const ItemInst* inst = container->GetItem(i);
if (inst) { if (!inst)
continue;
const Item_Struct* item = GetItem(inst->GetItem()->ID); const Item_Struct* item = GetItem(inst->GetItem()->ID);
if (item) { if (!item)
continue;
if(first) { if(first) {
pos += snprintf(pos, 19, "%d", item->ID); buf2 += StringFormat("%d", item->ID);
first = false; first = false;
} else { } else
pos += snprintf(pos, 19, ",%d", item->ID); buf2 += StringFormat(",%d", item->ID);
}
sum += item->ID; sum += item->ID;
count++; count++;
} }
}
}
*pos = '\0';
if(count < 1) { if(count == 0)
return(false); //no items == no recipe return false; //no items == no recipe
}
qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id " std::string query = StringFormat("SELECT tre.recipe_id "
"FROM tradeskill_recipe_entries AS tre " "FROM tradeskill_recipe_entries AS tre "
"INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) " "INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) "
"WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount > 0) " "WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount > 0) "
"OR ( tre.item_id %s AND tre.iscontainer=1 ))" "OR ( tre.item_id %s AND tre.iscontainer=1 ))"
"GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u " "GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u "
" AND sum(tre.item_id * tre.componentcount) = %u", buf2, containers, count, sum); "AND sum(tre.item_id * tre.componentcount) = %u",
buf2.c_str(), containers.c_str(), count, sum);
if (!RunQuery(query, qlen, errbuf, &result)) { auto results = QueryDatabase(query);
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query); if (!results.Success()) {
safe_delete_array(query); LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query.c_str());
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, error: %s", errbuf); LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, error: %s", results.ErrorMessage().c_str());
return(false); return false;
} }
safe_delete_array(query);
qcount = mysql_num_rows(result); if (results.RowCount() > 1) {
if(qcount > 1) {
//multiple recipes, partial match... do an extra query to get it exact. //multiple recipes, partial match... do an extra query to get it exact.
//this happens when combining components for a smaller recipe //this happens when combining components for a smaller recipe
//which is completely contained within another recipe //which is completely contained within another recipe
first = true; first = true;
pos = buf2; uint32 index = 0;
for (i = 0; i < qcount; i++) { buf2 = "";
row = mysql_fetch_row(result); for (auto row = results.begin(); row != results.end(); ++row, ++index) {
uint32 recipeid = (uint32)atoi(row[0]); uint32 recipeid = (uint32)atoi(row[0]);
if(first) { if(first) {
pos += snprintf(pos, 19, "%u", recipeid); buf2 += StringFormat("%u", recipeid);
first = false; first = false;
} else { } else
pos += snprintf(pos, 19, ",%u", recipeid); buf2 += StringFormat(",%u", recipeid);
}
//length limit on buf2 //length limit on buf2
if(i == 214) { //Maximum number of recipe matches (19 * 215 = 4096) if(index == 214) { //Maximum number of recipe matches (19 * 215 = 4096)
LogFile->write(EQEMuLog::Error, "GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched %u of %u possible entries.", i + 1, qcount); LogFile->write(EQEMuLog::Error, "GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched %u of %u possible entries.", index + 1, results.RowCount());
break; break;
} }
} }
qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id" query = StringFormat("SELECT tre.recipe_id "
"FROM tradeskill_recipe_entries AS tre " "FROM tradeskill_recipe_entries AS tre "
"WHERE tre.recipe_id IN (%s) " "WHERE tre.recipe_id IN (%s) "
"GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u " "GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u "
" AND sum(tre.item_id * tre.componentcount) = %u", buf2, count, sum); "AND sum(tre.item_id * tre.componentcount) = %u", buf2.c_str(), count, sum);
auto results = QueryDatabase(query);
if (!RunQuery(query, qlen, errbuf, &result)) { if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query); LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query.c_str());
safe_delete_array(query); LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str());
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf); return false;
return(false);
} }
safe_delete_array(query);
qcount = mysql_num_rows(result);
} }
if(qcount < 1) if (results.RowCount() < 1)
return(false); return false;
if(qcount > 1) if(results.RowCount() > 1) {
{
//The recipe is not unique, so we need to compare the container were using. //The recipe is not unique, so we need to compare the container were using.
uint32 containerId = 0; uint32 containerId = 0;
if(some_id) { //Standard container if(some_id) //Standard container
containerId = some_id; containerId = some_id;
} else if(c_type)//World container
else if(c_type) { //World container
containerId = c_type; containerId = c_type;
} else //Invalid container
else { //Invalid container return false;
return(false);
query = StringFormat("SELECT tre.recipe_id "
"FROM tradeskill_recipe_entries AS tre "
"WHERE tre.recipe_id IN (%s) "
"AND tre.item_id = %u;", buf2.c_str(), containerId);
results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query.c_str());
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str());
return false;
} }
qlen = MakeAnyLenString(&query,"SELECT tre.recipe_id FROM tradeskill_recipe_entries as tre WHERE tre.recipe_id IN (%s)" if(results.RowCount() == 0) { //Recipe contents matched more than 1 recipe, but not in this container
" AND tre.item_id = %u;",buf2,containerId);
if (!RunQuery(query, qlen, errbuf, &result)) {
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query);
safe_delete_array(query);
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf);
return(false);
}
safe_delete_array(query);
uint32 resultRowTotal = mysql_num_rows(result);
if(resultRowTotal == 0) { //Recipe contents matched more than 1 recipe, but not in this container
LogFile->write(EQEMuLog::Error, "Combine error: Incorrect container is being used!"); LogFile->write(EQEMuLog::Error, "Combine error: Incorrect container is being used!");
return(false); return false;
}
if(resultRowTotal > 1) { //Recipe contents matched more than 1 recipe in this container
LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique! %u matches found for container %u. Continuing with first recipe match.", resultRowTotal, containerId);
}
} }
row = mysql_fetch_row(result); if (results.RowCount() > 1) //Recipe contents matched more than 1 recipe in this container
LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique! %u matches found for container %u. Continuing with first recipe match.", results.RowCount(), containerId);
}
auto row = results.begin();
uint32 recipe_id = (uint32)atoi(row[0]); uint32 recipe_id = (uint32)atoi(row[0]);
mysql_free_result(result);
//Right here we verify that we actually have ALL of the tradeskill components.. //Right here we verify that we actually have ALL of the tradeskill components..
//instead of part which is possible with experimentation. //instead of part which is possible with experimentation.
//This is here because something's up with the query above.. it needs to be rethought out //This is here because something's up with the query above.. it needs to be rethought out
bool has_components = true; bool has_components = true;
char TSerrbuf[MYSQL_ERRMSG_SIZE]; query = StringFormat("SELECT item_id, componentcount "
char *TSquery = 0; "FROM tradeskill_recipe_entries "
MYSQL_RES *TSresult; "WHERE recipe_id = %i AND componentcount > 0",
MYSQL_ROW TSrow; recipe_id);
if (RunQuery(TSquery, MakeAnyLenString(&TSquery, "SELECT item_id, componentcount from tradeskill_recipe_entries where recipe_id=%i AND componentcount > 0", recipe_id), TSerrbuf, &TSresult)) { results = QueryDatabase(query);
while((TSrow = mysql_fetch_row(TSresult))!=nullptr) { if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in tradeskill verify query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec);
}
if (results.RowCount() == 0)
return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec);
for (auto row = results.begin(); row != results.end(); ++row) {
int ccnt = 0; int ccnt = 0;
for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) { for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) {
const ItemInst* inst = container->GetItem(x); const ItemInst* inst = container->GetItem(x);
if(inst){ if(!inst)
continue;
const Item_Struct* item = GetItem(inst->GetItem()->ID); const Item_Struct* item = GetItem(inst->GetItem()->ID);
if (item) { if (!item)
if(item->ID == atoi(TSrow[0])){ continue;
if(item->ID == atoi(row[0]))
ccnt++; ccnt++;
} }
}
}
}
if(ccnt != atoi(TSrow[1]))
has_components = false;
}
mysql_free_result(TSresult);
} else {
LogFile->write(EQEMuLog::Error, "Error in tradeskill verify query: '%s': %s", TSquery, TSerrbuf);
}
safe_delete_array(TSquery);
if(has_components == false){
if(ccnt != atoi(row[1]))
return false; return false;
} }
return(GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec)); return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec);
} }
bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id, bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id,