PDA

View Full Version : Fix for tradskill bug


Knightly
01-18-2008, 01:38 PM
Right now, to return a tradeskill item you have to have two entries for that item in the tradeskill_recipe_entries table. The first entry tells the database how many to use and the second entry tells the database how many to return (and to use 0).

Obviously this is not the way that the schema was intended and it can easily be fixed in the code.

In zone\tradeskills.cpp find:
//Pull the on-fail items...
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
" WHERE failcount>0 AND componentcount=0 AND recipe_id=%u", recipe_id);

and change it to:
//Pull the on-fail items...
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
" WHERE failcount>0 AND componentcount>0 AND recipe_id=%u", recipe_id);

What this does is change the request from "Tell me all items and how many of this item I should return where I've used 0 of them" to "Tell me all items and how many of this item I should return where I've used at least one of them."

This is what I believe was intended by that line of code. The first code snippet says "I only want to return items that weren't required for the recipe." The second snippet says "I only want to return items that were required for the recipe."

HOWEVER, it is my feeling that I should be able to return any item I want, whether it was used in the recipe or not. For example: When I'm making Bear Fillet in Cream and I combine my Filleted Bear with my Creamy Fennel Sauce, I may not be paying attention and fail. Who's to say that my failure can't return a Sticky Brown Mess?

I vaguely remember something like this happening in EQ Live, on a failure neither of the items you put in are returned, but you get a separate item back. My wife tells me I am wrong and since I can't find the recipe, I may well be. But just in case I'm not, you could change the code to:
//Pull the on-fail items...
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
" WHERE failcount>0 AND recipe_id=%u", recipe_id);

Either way, the existing code should be fixed.

::WARNING1:: The first change above will require you to change your database in the case where you did not make the failcount match for the item where you added the 0 use component.

::WARNING2:: The second change above will require you to change your database in the case where you did make the failcount match for th eitem where you added the 0 use component.

::Hope:: I'm hoping someone else will update the databases themselves to fix this, but it may require double checking around 3500 recipies. It can be done programatically if your database is consistent (and you know exactly how it is consistent). If someone can tell me which of the above fixes should be merged into the code and how each database's recipies are done then I will start making database changes appropriately.

Knightly
01-27-2008, 09:43 PM
Funnily enough, I didn't even realize that success was a problem as well until you said it and I looked at the code.

I started off writing the backwards compatibility, but it turns out it's actually easier for me to update the database than it is to write the backwards compatibility code.

The reason is because the best way to do the backwards compatibility would be to add a new column (isnewrecipe) and set all the old recipes to 0. All the new recipes would then be set to 1 and the code would be changed to first check if an isnewrecipe exists for what you're trying to combine and then fall back on the old recipe. The problem with that is there's a LOT of places in the code where that where clause would need to be changed. I'd end up mucking up the code pretty bad as an interim fix.

Again, I actually started on that, but I needed something to check with so I generated a couple of recipes in the new format and wrote a quick script to compare them to the old. Through this, I found quite a few inconsistencies (as you mention above) with the existing database.

After running the script to convert all of the old recipes to the new format, I then compared the new format recipes with the old. I compare them in plain English because it makes it easier on me and better to test. Here is an example of the output:
Recipe mismatch for recipe #3453:
Old Method: To make recipe #3453 (tarnished halberd) you need 1 of item #5024 (1xRusty Halberd) 1 of item #12056 (1xSharpening Stone) inside item #17 () and if you fail you get back nothing but if you succeed you get back 1 of item #67383 (1xTarnished Halberd).
New Method: To make recipe #3453 (tarnished halberd) you need 1 of item #5024 (1xRusty Halberd) 1 of item #12056 (1xSharpening Stone) inside item #17 () and if you fail you get back 1 of item #5024 (1xRusty Halberd) but if you succeed you get back 1 of item #67383 (1xTarnished Halberd).
Mismatch in fails:
Old Method: and if you fail you get back nothing
New Method: and if you fail you get back 1 of item #5024 (1xRusty Halberd)

Because it got converted to the new format properly, it means that the old recipe for tarnished halberd has item 5024 (rusty halberd) with failcount = 1 and componentcount = 1 in the same line. For the old code, the recipe is actually wrong.

Again, each new recipe is verified against the old recipe output, but now I'm stuck with how to fix it. I'm thinking the only consistent way to do it (with new recipes being added all the time) is to submit all of the necessary changes to the old format (on the PEQ side) and then rerun the script until all inconsistencies have been taken care of. In this case, it would be setting the item 5024 failcount to 0 in recipe 3453 and then adding another entry for the fail return.

There's quite a few items where this crops up. If nothing else, at least a lot of recipes will get fixed. Thoughts?

WildcardX
02-12-2008, 06:14 AM
Unless this "fix" provides backwards compatibility to the existing 3500 recipes already in the database, I'm afraid we cant commit this to the server code. I don't see think breaking about 3500 recipes is worth the primary benefit of conserving some space in this table.

Either add in a way to provide backward compatibility or figure out a query to mass edit the existing recipes and then repost and I'll reconsider.

Knightly
02-12-2008, 05:54 PM
or figure out a query to mass edit the existing recipes

Unfortunately, to do this you'd need every database to be consistent and they're not. Even within a single database (PEQ for example) there is very little consistency to the recipes because of how people currently read the information available on how to add a recipe.

The best I can do as far as that goes is to tell everyone HOW to change their existing database. Or (in the case of PEQ) post all of the changes to make it so that it is consistent enough to run queries against.

My actual plan is (once I finish PEQ) to post the code that I used to make the decisions on what to change. Right now, the code isn't perfect so I have to make a lot of tweaks manually. It has helped me find a lot of errors in the existing recipes, but it also creates a lot of errors. Of course, the more errors it creates, the more tweaks I can make until we're good. So far I've got fails and combines taken care of, but it doesn't work out successes very well (again, consistency due to the way that it looks like it should work vs how it acutally works and how people read it).

As I mentioned above, it's possible to write the backwards compatibility (and if you really really want me to, I will) but from my point of view it's easier to convert the existing databases than it is to write the backwards compatibility. And once I have the code finished for that I"ll post it for everyone.

Knightly
02-12-2008, 06:17 PM
Bah, five minute rule. I also want to mention that changing the EQEmu code to take into account both cases will be messy for readability on the code. That's the main reason that I didn't recommend that method.

Also, my efforts in this area are not intended to reduce space in the table (it's a negligible reduction at best). I am more interested in making the databases consistent so that it's easier and more intuitive to add recipes.

WildcardX
02-13-2008, 05:51 AM
It might not be as intuitive to add recipes, but this disadvantage can be mitigated through admin experience and tools designed to create recipes for the less experienced. I'd still prefer to keep the recipe system the way it is instead of implementing something that might be more intuitive but affects so many existing recipes.

Your welcome to keep pursing this issue and I'll be happy to reconsider a submitted viable solution, but maybe your time will be better spent on another issue thats more compelling.

OOC: Not trying to discourage you here.

WildcardX
02-13-2008, 08:56 AM
One mans junk...

WildcardX
02-13-2008, 10:19 AM
Let me be clear. We aren't going to start to decide what to keep or what to ditch. Given the long list of things that need to be fixed, this one rates pretty low, in my opinion. few things in the emulator are perfect, anyway, but recipe system is working fine as it is.

Again, I don't want to discourage anyone from contributing though.

WildcardX
02-13-2008, 11:57 AM
Not to be a drag, but the only people who should post in this thread are Knightly and myself or another developer like KLS. Please take discussion elsewhere.

Knightly
02-14-2008, 09:25 AM
I put some thought into it and turns out when I said:
Unfortunately, to do this you'd need every database to be consistent and they're not.

I was wrong. I was looking at it from the wrong direction (going from ingredients in the old recipe to ingredients in the new recipe). This allowed me to catch a lot of tradeskills where people had entered them in wrong, but as a conversion script it requires too much manual work.

Looking at it from the other side, where I know exactly what we want to get as a result makes it much more easily scripted.

I realize that most everyone already knows how to work around this (and that all of the tools take the query differences into account), but just from looking at the PEQ database I was able to find at least 30 counts where whoever was entering the recipe made the mistake of not taking into account that you can't return a component for a recipe without at least a second entry.

Granted, 1% of recipes is a very very small number. I'm not even sure why this bothers me so much. It's been years since I did 1NF conversions.

At any rate, the following steps will convert any database to the proposed format. It does require PHP because that's the language I write fastest in, but that shouldn't be a problem for anyone wanting to do a database conversion.

Always back up your database before running anything against it no matter how safe the person who wrote it says it is.

Step 1 -- Modify your table so we can do comparisons:
ALTER TABLE `tradeskill_recipe_entries` ADD COLUMN `isnewrecipe` TINYINT(1) NOT NULL DEFAULT 1 AFTER `iscontainer`;
UPDATE `tradeskill_recipe_entries` SET isnewrecipe=0;

Step 2 -- Generate new recipes: (ConvertRecipes.php)
<?php
//Modify the following variables to match your database
$dbhost = "localhost";
$database = "projecteq";
$username = "databaseuser";
$password = "databasepass";
$timeout = 60000; // in seconds
//stop editing here

set_time_limit($timeout);

$link = mysql_connect($dbhost, $username, $password)
or die('Could not connect: ' . mysql_error());
//First we get all of the old recipe_id information
$query = "SELECT DISTINCT recipe_id FROM `$database`.`tradeskill_recipe_entries` WHERE isnewrecipe=0;";
$result = mysql_query($query)
or die(mysql_error());
print "Converting recipes, this may take a while.";
//Now we need to loop through all of those IDs we just got:
while($row = mysql_fetch_assoc($result)) {
$recipe_ID = $row['recipe_id'];
$newrecipe = getRecipeComponentsArray($recipe_ID, $database);
$newrecipe = getRecipeContainer($recipe_ID, $newrecipe, $database);
$newrecipe = getRecipeFailureArray($recipe_ID, $newrecipe, $database);
$newrecipe = getRecipeSuccessArray($recipe_ID, $newrecipe, $database);
foreach ($newrecipe as $key => $value) {
if($value["componentcount"] == Null) {
$value["componentcount"] = 0;
}
if($value["iscontainer"] == Null) {
$value["iscontainer"] = 0;
}
if($value["successcount"] == Null) {
$value["successcount"] = 0;
}
if($value["failcount"] == Null) {
$value["failcount"] = 0;
}
if($value["componentcount"] == Null) {
$value["componentcount"] = 0;
}
if ($key == Null) {
//Do nothing if we don't have an item ID
}
else {
$insertquery = "INSERT INTO `$database`.`tradeskill_recipe_entries` (recipe_id,item_id,successcount,failcount,componen tcount,iscontainer,isnewrecipe) VALUES ($recipe_ID, $key, " . $value["successcount"] . ", " . $value["failcount"] . ", " . $value["componentcount"] . ", " . $value["iscontainer"] . ", 1);";
//echo $insertquery . "\n";
mysql_query($insertquery)
or die (mysql_error());
}
}
}
print "and DONE!";

function getRecipeComponentsArray($func_recipeid, $func_database) {
$func_query = "SELECT item_id, componentcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE recipe_id = $func_recipeid AND componentcount > 0 AND isnewrecipe=0 ORDER BY item_id";
$func_result = mysql_query($func_query)
or die(mysql_error());
while ($func_row = mysql_fetch_assoc($func_result)) {
$func_recipereturn[$func_row['item_id']]["componentcount"] = $func_recipereturn[$func_row['item_id']]["componentcount"] + $func_row['componentcount'];
}
return $func_recipereturn;
}

function getRecipeContainer($func_recipeid, $func_recipereturn, $func_database) {
$func_query = "SELECT item_id FROM `$func_database`.`tradeskill_recipe_entries` WHERE recipe_id = $func_recipeid AND iscontainer = 1 AND isnewrecipe=0 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$func_row = mysql_fetch_assoc($func_result);
$func_recipereturn[$func_row['item_id']]["iscontainer"] = 1;
return $func_recipereturn;
}

function getRecipeFailureArray($func_recipeid, $func_recipereturn, $func_database) {
$func_query = "SELECT item_id, failcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE failcount>0 AND componentcount=0 AND recipe_id=$func_recipeid AND isnewrecipe=0 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
while ($func_row = mysql_fetch_assoc($func_result)) {
$func_recipereturn[$func_row['item_id']]["failcount"] = $func_recipereturn[$func_row['item_id']]["failcount"] + $func_row['failcount'];
}
return $func_recipereturn;
}

function getRecipeSuccessArray($func_recipeid, $func_recipereturn, $func_database) {
$func_query = "SELECT item_id, successcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE successcount>0 AND componentcount=0 AND recipe_id=$func_recipeid AND isnewrecipe=0 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
while ($func_row = mysql_fetch_assoc($func_result)) {
$func_recipereturn[$func_row['item_id']]["successcount"] = $func_recipereturn[$func_row['item_id']]["successcount"] + $func_row['successcount'];
}
return $func_recipereturn;
}
?>

Knightly
02-14-2008, 09:38 AM
Step 3 -- Compare recipes using the old format to recipes using the new format: (CompareTradeskillMethods.php)
<?php
//Modify the following variables to match your database
$dbhost = "localhost";
$database = "projecteq";
$username = "databaseuser";
$password = "databasepass";
$timeout = 600; // in seconds
//stop editing here

set_time_limit($timeout);

$link = mysql_connect($dbhost, $username, $password)
or die('Could not connect: ' . mysql_error());

//First we get all of the old recipe_id information
$query = "SELECT DISTINCT recipe_id FROM `$database`.`tradeskill_recipe_entries` WHERE isnewrecipe=0;";
$result = mysql_query($query)
or die(mysql_error());

echo "<html>";
echo "<body>";
//Now we need to loop through all of those IDs we just got:
while($row = mysql_fetch_assoc($result)) {
$oldstring = "This is the old string.";
$newstring = "This is the new string.";
$recipeid = $row['recipe_id'];
//I realize this is a run on sentence, sue me.
$oldcomponents = "To make recipe #$recipeid (" . getRecipeName($recipeid, $database) . ") you need" . getRecipeComponents($recipeid, $database);
$newcomponents = "To make recipe #$recipeid (" . getRecipeName($recipeid, $database) . ") you need" . getRecipeComponents($recipeid, $database, true);
$oldcontainer = " inside item #" . getContainer($recipeid, $database);
$newcontainer = " inside item #" . getContainer($recipeid, $database, true);
$oldfails = " and if you fail you get back " . getOldFailures($recipeid, $database);
$newfails = " and if you fail you get back " . getNewFailures($recipeid, $database);
$oldsuccess = " but if you succeed you get back " . getOldSuccesses($recipeid, $database) . ".";
$newsuccess = " but if you succeed you get back " . getNewSuccesses($recipeid, $database) . ".";
$oldstring = $oldcomponents . $oldcontainer . $oldfails . $oldsuccess;
$newstring = $newcomponents . $newcontainer . $newfails . $newsuccess;
if ($oldstring == $newstring) {
if (!(strpos($oldstring, "an error") === false) && !(strpos($newstring, "an error") === false)) {
echo "<br />Error in recipe #$recipeid<br />";
echo "Old Method: $oldstring<br />";
echo "New Method: $newstring<br />";
}
}
else {
echo "<br />Recipe mismatch for recipe #$recipeid:<br />";
echo "Old Method: $oldstring<br />";
echo "New Method: $newstring<br />";
if (!($oldcomponents == $newcomponents)) {
echo "Mismatch in components:<br />";
echo "Old Method: $oldcomponents<br />";
echo "New Method: $newcomponents<br />";
}
if (!($oldcontainer == $newcontainer)) {
echo "Mismatch in container:<br />";
echo "Old Method: $oldcontainer<br />";
echo "New Method: $newcontainer<br />";
}
if (!($oldfails == $newfails)) {
echo "Mismatch in fails:<br />";
echo "Old Method: $oldfails<br />";
echo "New Method: $newfails<br />";
}
if (!($oldsuccess == $newsuccess)) {
echo "Mismatch in successes:<br />";
echo "Old Method: $oldsuccess<br />";
echo "New Method: $newsuccess<br />";
}
}
}
echo "End";
echo "</body>";
echo "</html>";
// ----Break for character limit -- See next post

Knightly
02-14-2008, 09:39 AM
// ----Resume from previous post
function getRecipeName($func_recipeid, $func_database) {
if ($func_recipeid == Null) {
return "an error";
}
else {
$func_query = "SELECT name FROM `$func_database`.`tradeskill_recipe` WHERE id = $func_recipeid;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$func_row = mysql_fetch_assoc($func_result);
return $func_row['name'];
}
}

function getItemName($func_itemid, $func_database) {
if ($func_itemid == Null) {
return "an error";
}
else {
$func_query = "SELECT name FROM `$func_database`.`items` WHERE id = $func_itemid;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$func_row = mysql_fetch_assoc($func_result);
return $func_row['name'];
}
}

function getRecipeComponents($func_recipeid, $func_database, $func_newformat = false) {
if ($func_recipeid == Null) {
return "an error";
}
else {
$func_query = "SELECT item_id, componentcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE recipe_id = $func_recipeid AND componentcount > 0 AND isnewrecipe=";
if ($func_newformat == true) {
$func_query = $func_query . "1 ";
}
else {
$func_query = $func_query . "0 ";
}
$func_query = $func_query . "ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$returnstring = "";
//For old recipe calculations
$currentitemid = -1;
$currentitemcount = 1;
while ($func_row = mysql_fetch_assoc($func_result)) {
//account for the old recipes giving you back 1 and 1 and 1 of an item instead of 3 of an item
if ($func_newformat == false) {
if ($currentitemid == $func_row['item_id']) {
$currentitemcount = $currentitemcount + $func_row['componentcount'];
}
else {
if (!($currentitemid == -1)) {
$returnstring = " " . $returnstring . $currentitemcount . " of item #" . $currentitemid . " (" . $currentitemcount . "x" . getItemName($currentitemid, $func_database) . ") ";
}
$currentitemid = $func_row['item_id'];
$currentitemcount = $func_row['componentcount'];
}
}
else {
$returnstring = " " . $returnstring . $func_row['componentcount'] . " of item #" . $func_row['item_id'] . " (" . $func_row['componentcount'] . "x" . getItemName($func_row['item_id'], $func_database) . ") ";
}
}
if ($func_newformat == false) {
$returnstring = " " . $returnstring . $currentitemcount . " of item #" . $currentitemid . " (" . $currentitemcount . "x" . getItemName($currentitemid, $func_database) . ") ";
}
if ($returnstring == ""){
$returnstring = "an error";
}
return $returnstring;
}
}

function getContainer($func_recipeid, $func_database, $func_newformat = false) {
if ($func_recipeid == Null) {
return "an error";
}
else {
$func_query = "SELECT item_id FROM `$func_database`.`tradeskill_recipe_entries` WHERE recipe_id = $func_recipeid AND iscontainer = 1 AND isnewrecipe=";
if ($func_newformat == true) {
$func_query = $func_query . "1 ";
}
else {
$func_query = $func_query . "0 ";
}
$func_query = $func_query . "ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$func_row = mysql_fetch_assoc($func_result);
return $func_row['item_id'] . " (" . getItemName($func_row['item_id'], $func_database) . ")";
}
}

function getOldFailures($func_recipeid, $func_database) {
if ($func_recipeid == Null) {
return "an error";
}
else {
//This is the query from the current EQEMU code, with two modifications:
//1. The ORDER BY clause has been added so that we can make the items we want come up first which makes the sentence we're forming easier to compare.
//2. The isnewrecipe identifier has been added since we only want to pull information from old recipies
$func_query = "SELECT item_id, failcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE failcount>0 AND componentcount=0 AND recipe_id=$func_recipeid AND isnewrecipe=0 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$returnstring = "";
while ($func_row = mysql_fetch_assoc($func_result)) {
$returnstring = " " . $returnstring . $func_row['failcount'] . " of item #" . $func_row['item_id'] . " (" . $func_row['failcount'] . "x" . getItemName($func_row['item_id'], $func_database) . ")";
}
if ($returnstring == "") {
$returnstring = "nothing";
}
return $returnstring;
}
}

function getNewFailures($func_recipeid, $func_database) {
if ($func_recipeid == Null) {
return "an error";
}
else {
//This is the query from the proposed EQEMU code, with two modifications:
//1. The ORDER BY clause has been added so that we can make the items we want come up first which makes the sentence we're forming easier to compare.
//2. The isnewrecipe identifier has been added since we only want to pull information from new recipies
$func_query = "SELECT item_id, failcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE recipe_id=$func_recipeid AND failcount>0 AND isnewrecipe=1 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$returnstring = "";
while ($func_row = mysql_fetch_assoc($func_result)) {
$returnstring = " " . $returnstring . $func_row['failcount'] . " of item #" . $func_row['item_id'] . " (" . $func_row['failcount'] . "x" . getItemName($func_row['item_id'], $func_database) . ")";
}
if ($returnstring == "") {
$returnstring = "nothing";
}
return $returnstring;
}
}

function getOldSuccesses($func_recipeid, $func_database) {
if ($func_recipeid == Null) {
return "an error";
}
else {
//This is the query from the current EQEMU code, with two modifications:
//1. The ORDER BY clause has been added so that we can make the items we want come up first which makes the sentence we're forming easier to compare.
//2. The isnewrecipe identifier has been added since we only want to pull information from old recipies
$func_query = "SELECT item_id, successcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE successcount>0 AND componentcount=0 AND recipe_id=$func_recipeid AND isnewrecipe=0 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$returnstring = "";
$currentitemid = -1;
$currentitemcount = 1;
while ($func_row = mysql_fetch_assoc($func_result)) {
if ($currentitemid == $func_row['item_id']) {
$currentitemcount = $currentitemcount + $func_row['successcount'];
}
else {
if (!($currentitemid == -1)) {
$returnstring = " " . $returnstring . $currentitemcount . " of item #" . $currentitemid . " (" . $currentitemcount . "x" . getItemName($currentitemid, $func_database) . ") ";
}
$currentitemid = $func_row['item_id'];
$currentitemcount = $func_row['successcount'];
}
}
$returnstring = " " . $returnstring . $currentitemcount . " of item #" . $currentitemid . " (" . $currentitemcount . "x" . getItemName($currentitemid, $func_database) . ") ";
//$returnstring = " " . $returnstring . $func_row['successcount'] . " of item #" . $func_row['item_id'] . " (" . $func_row['successcount'] . "x" . getItemName($func_row['item_id'], $func_database) . ") ";
if ($returnstring == "") {
$returnstring = "an error";
}
return $returnstring;
}
}

function getNewSuccesses($func_recipeid, $func_database) {
if ($func_recipeid == Null) {
return "an error";
}
else {
//This is the query from the proposed EQEMU code, with two modifications:
//1. The ORDER BY clause has been added so that we can make the items we want come up first which makes the sentence we're forming easier to compare.
//2. The isnewrecipe identifier has been added since we only want to pull information from new recipies
$func_query = "SELECT item_id, successcount FROM `$func_database`.`tradeskill_recipe_entries` WHERE recipe_id=$func_recipeid AND successcount>0 AND isnewrecipe=1 ORDER BY item_id;";
$func_result = mysql_query($func_query)
or die(mysql_error());
$returnstring = "";
while ($func_row = mysql_fetch_assoc($func_result)) {
$returnstring = " " . $returnstring . $func_row['successcount'] . " of item #" . $func_row['item_id'] . " (" . $func_row['successcount'] . "x" . getItemName($func_row['item_id'], $func_database) . ") ";
}
if ($returnstring == "") {
$returnstring = "an error";
}
return $returnstring;
}
}
?>


Note: This will show you any place where your recipes do not match. You just need to look at the web page that is generated and make sure that it is correct. It will also generate errors for some recipes, you just need to check to make sure these errors are legitimate. For example: PEQ has some test recipes that don't have containers...those recipes will generate an error here. As long as the error is the same for "Old" as "New" then the conversion worked. The conversion converts broken recipes just the same as it converts working recipes.

Knightly
02-14-2008, 09:40 AM
Step 4 -- Remove old recipes and modify table:
DELETE FROM `tradeskill_recipe_entries` WHERE isnewrecipe=0;
ALTER TABLE `tradeskill_recipe_entries` DROP COLUMN `isnewrecipe`;

Step 5 -- Modify EQEmu code (will post this later)

cavedude
02-14-2008, 10:30 AM
I'll certainly give this a try and get back to you as to how it works! If it does indeed do the trick, then I have no problem making this change on PEQ after the correction code has been added to developer SVN.

Knightly
02-14-2008, 10:44 AM
Step 5 -- Step 5: Open Tradeskills.cpp and make the following changes:
Change:
//Pull the on-success items...
qlen = MakeAnyLenString(&query, "SELECT item_id,successcount FROM tradeskill_recipe_entries"
" WHERE successcount>0 AND componentcount=0 AND recipe_id=%u", recipe_id);

To:
//Pull the on-success items...
qlen = MakeAnyLenString(&query, "SELECT item_id,successcount FROM tradeskill_recipe_entries"
" WHERE successcount>0 AND recipe_id=%u", recipe_id);

Change:
//Pull the on-fail items...
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
" WHERE failcount>0 AND componentcount=0 AND recipe_id=%u", recipe_id);

To:
//Pull the on-fail items...
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
" WHERE failcount>0 AND recipe_id=%u", recipe_id);