Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
  #2  
Old 10-26-2008, 09:30 PM
AndMetal
Developer
 
Join Date: Mar 2007
Location: Ohio
Posts: 648
Default

Quote:
Originally Posted by seveianrex View Post
The client interprets the AA Index which is why we store that value in the DB. We pull the value for each AA from the DB and send it to the client in the process ZoneDatabase:GetAASkillVars() (aa.cpp).
That's what it looks like, since all we do with it is put it into the OP_SendAATable packet & send that off to the client. As a result, the client gets it in the same order we're getting it from the DB
Code:
RunQuery(query, MakeAnyLenString(&query, "SELECT cost, max_level, hotkey_sid, hotkey_sid2, "
		"title_sid, desc_sid, type, prereq_skill, prereq_minpoints, spell_type, spell_refresh, "
		"classes, berserker,spellid,class_type,name,cost_inc"
		" FROM altadv_vars WHERE skill_id=%i", skill_id), errbuf, &result)
which is sorted by the index number since we don't have a SORT BY clause.

I'm wondering if we can do all of this with a modified DB query (using some sort of subquery probably) that translates a prereq_skill as a skill_id to the index #?

After working over this for a bit (with some inspiration), here's the query I came up with:
Code:
SET @row = 0;
SELECT 
	a.cost, 
	a.max_level, 
	a.hotkey_sid, 
	a.hotkey_sid2, 
	a.title_sid, 
	a.desc_sid, 
	a.type, 
	COALESCE(
		(
		SELECT 
			prereq_index_num 
		FROM 
			(
			SELECT 
				@row := @row + 1 AS prereq_index_num 
			FROM 
				altadv_vars
			) AS prereq_conv 
		WHERE 
			prereq_skill = prereq_index_num
		), 
		0)  AS prereq_skill_index, 
	a.prereq_minpoints, 
	a.spell_type, 
	a.spell_refresh, 
	a.classes, 
	a.berserker, 
	a.spellid, 
	a.class_type, 
	a.name, 
	a.cost_inc 
FROM 
	altadv_vars a 
;
which you actually have to execute as this for it to work properly:
Code:
SET @row = 0;
SELECT a.cost, a.max_level, a.hotkey_sid, a.hotkey_sid2, a.title_sid, a.desc_sid, a.type, COALESCE((SELECT prereq_index_num FROM (SELECT @row := @row + 1 AS prereq_index_num FROM altadv_vars) AS prereq_conv WHERE prereq_skill = prereq_index_num), 0) AS prereq_skill_index, a.prereq_minpoints, a.spell_type, a.spell_refresh, a.classes, a.berserker, a.spellid, a.class_type, a.name, a.cost_inc FROM altadv_vars a;
The only problem I've run into with the query is being able to manipulate the derived column, prereq_skill_index, in the where clause:
Code:
mysql> SELECT a.cost, a.max_level, a.hotkey_sid, a.hotkey_sid2, a.title_sid, a.desc_sid, a.type, COALESCE((SELECT prereq_index_num FROM (SELECT @row := @row + 1 AS prereq_index_num FROM altadv_vars) AS prereq_conv WHERE prereq_skill = prereq_index_num), 0) AS prereq_skill_index, a.prereq_minpoints, a.spell_type, a.spell_refresh, a.classes, a.berserker, a.spellid, a.class_type, a.name, a.cost_inc FROM altadv_vars a WHERE prereq_index_num > 0;
ERROR 1054 (42S22): Unknown column 'prereq_index_num' in 'where clause'
However, at this point, we don't really need to do anything with it, and even if we did, we should be able to utilize the still existing prereq_skill column in the altadv_vars table.

We could definitely iterate through the possible AA IDs, but I think this would be a lot cleaner & less resource intensive (relatively, since we're only talking about a few hundred to a few thousand loops, depending on how quickly we find our match).

So, if we decide to go this route, we can do this:
in zone/AA.cpp, around line 1241 in ZoneDatabase::GetAASkillVars(), change
Code:
	if (RunQuery(query, MakeAnyLenString(&query, "SET @row = 0"), errbuf, &result)) {	//initialize "row" variable in database for next query
		query = 0;	//reset for next query
		if (RunQuery(query, MakeAnyLenString(&query, 
			"SELECT cost, "
				"max_level, "
				"hotkey_sid, "
				"hotkey_sid2, "
				"title_sid, "
				"desc_sid, "
				"type, "
				"COALESCE("	//so we can return 0 if it's null
					"("	//this is our derived table that has the row # that we can SELECT from, because the client is stupid
					"SELECT "
						"prereq_index_num "
					"FROM "
						"("
						"SELECT "
							"@row := @row + 1 AS prereq_index_num "
						"FROM "
							"altadv_vars"
						") AS prereq_conv "
					"WHERE "
						"prereq_skill = prereq_index_num"
					"), "
					"0)  AS prereq_skill_index, "
				"prereq_minpoints, "
				"spell_type, "
				"spell_refresh, "
				"classes, "
				"berserker, "
				"spellid, "
				"class_type, "
				"name, "
				"cost_inc "
			" FROM altadv_vars WHERE skill_id=%i", skill_id), errbuf, &result)) {
			safe_delete_array(query);
			if (mysql_num_rows(result) == 1) {
				int total_abilities = GetTotalAALevels(skill_id);
				int totalsize = total_abilities * sizeof(AA_Ability) + sizeof(SendAA_Struct);
				
				buffer = new uchar[totalsize];
				memset(buffer,0,totalsize);
				sendaa = (SendAA_Struct*)buffer;
				
				row = mysql_fetch_row(result);
				
				//ATOI IS NOT UNISGNED LONG-SAFE!!!
				
				sendaa->cost = atoul(row[0]);
				sendaa->cost2 = sendaa->cost;
				sendaa->max_level = atoul(row[1]);
				sendaa->hotkey_sid = atoul(row[2]);
				sendaa->id = skill_id;
				sendaa->hotkey_sid2 = atoul(row[3]);
				sendaa->title_sid = atoul(row[4]);
				sendaa->desc_sid = atoul(row[5]);
				sendaa->type = atoul(row[6]);
				sendaa->prereq_skill = atoul(row[7]);
				sendaa->prereq_minpoints = atoul(row[8]);
				sendaa->spell_type = atoul(row[9]);
				sendaa->spell_refresh = atoul(row[10]);
				sendaa->classes = atoul(row[11]);
				sendaa->berserker = atoul(row[12]);
				sendaa->last_id = 0xFFFFFFFF;
				sendaa->current_level=1;
				sendaa->spellid = atoul(row[13]);
				sendaa->class_type = atoul(row[14]);
				strcpy(sendaa->name,row[15]);
				
				sendaa->total_abilities=total_abilities;
				if(sendaa->max_level > 1)
					sendaa->next_id=skill_id+1;
				else
					sendaa->next_id=0xFFFFFFFF;
				
				sendaa->cost_inc = atoi(row[16]);
			}
			mysql_free_result(result);
		} else {
			LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query, errbuf);
			safe_delete_array(query);
		}
	} else {
		LogFile->write(EQEMuLog::Error, "Error in GetAASkillVars '%s': %s", query, errbuf);
		safe_delete_array(query);
	}
On a side note, I think this may also be a good opportunity to merge the classes & berserker columns in the database, since they can be OR'd together, and separate them out in the same function.

Any feedback?
__________________
GM-Impossible of 'A work in progress'
A non-legit PEQ DB server
How to create your own non-legit server

My Contributions to the Wiki
Reply With Quote
 

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 03:58 AM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3