View Single Post
  #1  
Old 02-14-2004, 06:45 PM
vesuvias
Fire Beetle
 
Join Date: Feb 2004
Posts: 17
Default My first contribution... Here goes nothing...

Forgive me if I do something taboo, I have only been following this scene for a little over a week. Any way I dove head first into the code and decided to fix a few things that were bugging me (err.. yeah).

Any way here is what I did:

-Zone Bind Points (added some fields to start_zones and fixed an issue that would crash the client if you died to your bind point)
-Fixed an issue that was causing you character creation skin selections to be lost, now everyone doesn't have to look the same (Yeeaa!!)

Additions

-the start_zone table now has support for wildcarding on selection this means that DB developers don't have to put in (number of selections on map screen) *(number of races) *(number of classes)*(number of dieties) = number records in the database. putting a -1 in of these fields in the DB basically selects all of the combinations for that field. So if I only wanted to have 1 starting point for each class I would put -1 in the diety, choice and race coloumn for each record.

When specifying start_zones just remeber this SQL statement (its the one we use now to get start_zones):
Code:
SELECT x,y,z,zone_id,bind_id,bind_x,bind_y,bind_z FROM start_zones WHERE (player_choice=%i OR  player_choice=-1) and (player_class=%i OR player_class=-1) and (player_deity=%i OR player_deity=-1) and (player_race=%i OR player_race=-1) ORDER BY select_rank DESC
select_rank allows you to assign importance to the start_zone record basically the more specific the start_zone record (records with more -1 wildcards are less specific) the greater the select_rank should be. A good rule is to start at 50 and for every wildcard you use subtract 10 from this value.

This allows you to specify things like I want all characters to start in the nexus as a default. However I want all warriors to start in Halas. This would require 2 records in the DB, one for the nexus with -1 for race,choice,class and diety and a select rank of say 10. And one for the warriors that go to halas and it would have -1 for race, choice, and diety and a select_rank of say 20. If later you wanted to further specify where agnostic warriors go, you would just add one more record with a higher select_rank.

Zoneing Fixes

well after I added that code I realised that bound characters that die crash thier clients (never knew that since I was never bound before). So I decided to hunt that bug down. It turns out that this peice of code was the culperit
Code:
					if (zc->zoneID != 0 && dead)
					{
#ifdef GUILDWARS
					if(animation > 65 && admin<80 && CheckCheat()){
						if(cheater || cheatcount>0){
							Message(15,"Cheater log updated...yup your busted,its not nice to cheat.");
							char descript[50]={0};
							sprintf(descript,"%s: %i","Death zone cheat");
							database.logevents(this->AccountName(),this->AccountID(),admin,this->GetName(),"none","Death zone cheat",descript,15);
							if(cheater==false){
								worldserver.SendEmoteMessage(0,0,0,13,"<Cheater Locator> We have found a cheater.  %s (Acct: %s) was just caught hacking, please show them what we think of hackers...",this->GetName(),this->AccountName());
								cheater=true;
							}
							cheatcount=0;
						}
						else
							cheatcount++;
					}
#else
					break;
#endif
					}
This section executes in the OP_ZoneChange case under handlepacket in client_process.cpp. Any way basically if you died and the zone change packet specified a zone (other than 0) then you would break??? You got a zone change requrest why wouldn't you want to finish it? Anyway taking out the break fixed the issue it seems.

I also cleaned up the code a little in OP_ZoneChange so you wouldn't do wierd things like go to -3,-3,-3 when there was a perfectly acceptable safe_zone to go too.

Character skins

The last thing I decided to tackle was character skins and this was acutually the hardest thing of all to debug. First I corrected struct that recieved info from the client on character creation as there were a few guessed at spots inside that struct. I did this through numerous tedious trial and error chracter creations (Ie create a gnome a certian way, then create a second gnome the exact same way except this time change just his beard and analysis the data we get).

After I got the data for CharCreate_Struct ok, I moved onto trying to figure out why these character specific skin changes never got back to client. It turns out that CharacterSelect_Struct had about 60 bytes of unknown data. So I then went through a fairly painful process of trying to figure out what order the data went in on its way back. Fortunatly I was able to figure it out finally. It was challenging though. Hope everyone can benefit from some of my work at least a little .

Here are the diffs:

First SQL changes

Code:
ALTER TABLE start_zones ADD bind_x FLOAT DEFAULT "0" NOT NULL
ALTER TABLE start_zones ADD bind_y FLOAT DEFAULT "0" NOT NULL
ALTER TABLE start_zones ADD bind_z FLOAT DEFAULT "0" NOT NULL
ALTER TABLE start_zones ADD select_rank TINYINT UNSIGNED DEFAULT "50" NOT NULL
Now the database.cpp diff:
Code:
Index: database.cpp
===================================================================
RCS file: /cvsroot/eqemu/eqemu/eqemu/Source/common/database.cpp,v
retrieving revision 1.1.1.11
diff -r1.1.1.11 database.cpp
1164,1165c1164
< 				cs->gender[char_num]	= pp->gender;
< 				cs->face[char_num]		= pp->face;
---
> 				cs->gender[char_num]	= pp->gender;				
1167a1167,1174
> 				cs->face[char_num]		= pp->face;
> 				cs->haircolor[char_num] = pp->haircolor;
> 				cs->beardcolor[char_num]= pp->beardcolor;
> 				cs->eyecolor2[char_num] = pp->eyecolor2;
> 				cs->eyecolor1[char_num] = pp->eyecolor1;
> 				cs->hair[char_num]		= pp->hairstyle;
> 				cs->beard[char_num]		= pp->beard;
> 				
6551c6558
< 	cout<<"Choice:"<<in_cc->start_zone<<endl;
---
> 	//cout<<"Choice:"<<in_cc->start_zone<<" Class:"<<in_cc->class_<<" Race:"<<in_cc->race<<" Diety:"<<in_cc->deity<<endl;
6556c6563,6564
< if (RunQuery(query, MakeAnyLenString(&query, "SELECT x,y,z,zone_id,bind_id FROM start_zones WHERE player_choice=%i and player_class=%i and player_deity=%i and player_race=%i", in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race), errbuf, &result)) {         
---
> 	int qLen = MakeAnyLenString(&query, "SELECT x,y,z,zone_id,bind_id,bind_x,bind_y,bind_z FROM start_zones WHERE (player_choice=%i OR  player_choice=-1) and (player_class=%i OR player_class=-1) and (player_deity=%i OR player_deity=-1) and (player_race=%i OR player_race=-1) ORDER BY select_rank DESC", in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race);
> if (RunQuery(query,qLen,errbuf,&result)) {         
6564c6572,6597
<          in_pp->bind_zone_id = atoi(row[4]); 
---
>          in_pp->bind_zone_id = atoi(row[4]);
> 		 //if we haven't set a bind_zone_id lets set it to the starting zone
> 		 if (in_pp->bind_zone_id ==0) in_pp->bind_zone_id = in_pp->zone_id; 
> 		 in_pp->bind_x = atof(row[5]);
> 		 in_pp->bind_y = atof(row[6]);
> 		 in_pp->bind_z = atof(row[7]);
> 		 //if bind x,y,z are all 0 then we need as a default to use the safe point
> 		 //for the bound zone
> 		 if (in_pp->bind_x ==0 && in_pp->bind_y ==0 && in_pp->bind_z ==0){
> 			char *query2 = 0;
> 			MYSQL_RES *result2;
> 			MYSQL_ROW row2;
> 			if (RunQuery(query2, MakeAnyLenString(&query2, "SELECT safe_x,safe_y,safe_z FROM zone WHERE zoneidnumber=%i",in_pp->bind_zone_id), errbuf, &result2)) {
> 				if (mysql_num_rows(result2) != 0) {
> 					row2 = mysql_fetch_row(result2); 
> 					in_pp->bind_x = atof(row[0]);
> 					in_pp->bind_y = atof(row[1]);
> 					in_pp->bind_z = atof(row[2]);
> 				}
> 				mysql_free_result(result2);
> 			} else {
> 				safe_delete_array(query2);
> 				LogFile->write(EQEMuLog::Error, "Database: could not find a zone entry in database for the starting bound zone.");	
> 			}
> 
> 		 }
6569c6602,6603
< 			LogFile->write(EQEMuLog::Error, "Database: could not find start_zones entry in database. Using Defaults..");
---
> 		  LogFile->write(EQEMuLog::Error, "Database: could not find a start_zones entry in database for this choice,class,race,diety. Using Defaults..");
> 		  
6574c6608,6609
< 		LogFile->write(EQEMuLog::Error, "Database: could not find start_zones table in database. Using Defaults..");
---
> 		LogFile->write(EQEMuLog::Error, errbuf);
> 		LogFile->write(EQEMuLog::Error, "Database: SQL Error. Using Defaults..");
eq_packet_structs.h Diff
Code:
Index: eq_packet_structs.h
===================================================================
RCS file: /cvsroot/eqemu/eqemu/eqemu/Source/common/eq_packet_structs.h,v
retrieving revision 1.1.1.10
diff -r1.1.1.10 eq_packet_structs.h
151c151,156
< /*1600*/	int8	unknown1600[60];	// ***Placeholder
---
> /*1600*/	int8	haircolor[10];	
> /*1610*/	int8    beardcolor[10];
> /*1620*/	int8	eyecolor2[10];	
> /*1630*/	int8    eyecolor1[10];
> /*1640*/	int8	hair[10];	
> /*1650*/	int8    beard[10];
604,606c609,611
< 	/*0068*/	int32	haircolor; //guess
< 	/*0072*/	int32	eyecolor1; //guess
< 	/*0076*/	int32	eyecolor2; //guess
---
> 	/*0068*/	int32	haircolor;
> 	/*0072*/	int32	beard;
> 	/*0076*/	int32	beardcolor;
638,640c643,645
< /*0128*/	int32	beard;//guess
< /*0132*/	int32	beardcolor;//guess
< /*0136*/	int32	face;
---
> /*0128*/	int32   face;
> /*0132*/	int32	eyecolor1;//its possiable we could have these switched
> /*0136*/	int32	eyecolor2;//since setting one sets the other we really can't check
and finally the client_process.cpp diff
Code:
Index: client_process.cpp
===================================================================
RCS file: /cvsroot/eqemu/eqemu/eqemu/Source/zone/client_process.cpp,v
retrieving revision 1.1.1.12
diff -r1.1.1.12 client_process.cpp
98,99c98
< 	#endif
< 	
---
> 	#endif	
1098c1097
< 				case OP_Death: {
---
> 				case OP_Death: {					
1100,1101c1099
< 						break;
< 					
---
> 						break;					
1585c1583
< 				case OP_ZoneChange: {
---
> 				case OP_ZoneChange: {					
1606a1605,1606
> 					
> #ifdef GUILDWARS
1609,1618c1609,1619
< #ifdef GUILDWARS
< 					if(animation > 65 && admin<80 && CheckCheat()){
< 						if(cheater || cheatcount>0){
< 							Message(15,"Cheater log updated...yup your busted,its not nice to cheat.");
< 							char descript[50]={0};
< 							sprintf(descript,"%s: %i","Death zone cheat");
< 							database.logevents(this->AccountName(),this->AccountID(),admin,this->GetName(),"none","Death zone cheat",descript,15);
< 							if(cheater==false){
< 								worldserver.SendEmoteMessage(0,0,0,13,"<Cheater Locator> We have found a cheater.  %s (Acct: %s) was just caught hacking, please show them what we think of hackers...",this->GetName(),this->AccountName());
< 								cheater=true;
---
> 						if(animation > 65 && admin<80 && CheckCheat()){
> 							if(cheater || cheatcount>0){
> 								Message(15,"Cheater log updated...yup your busted,its not nice to cheat.");
> 								char descript[50]={0};
> 								sprintf(descript,"%s: %i","Death zone cheat");
> 								database.logevents(this->AccountName(),this->AccountID(),admin,this->GetName(),"none","Death zone cheat",descript,15);
> 								if(cheater==false){
> 									worldserver.SendEmoteMessage(0,0,0,13,"<Cheater Locator> We have found a cheater.  %s (Acct: %s) was just caught hacking, please show them what we think of hackers...",this->GetName(),this->AccountName());
> 									cheater=true;
> 								}
> 								cheatcount=0;
1620c1621,1622
< 							cheatcount=0;
---
> 							else
> 								cheatcount++;
1622,1623d1623
< 						else
< 							cheatcount++;
1625,1626d1624
< #else
< 					break;
1628c1626
< 					}
---
> 
1652,1655c1650,1651
< 		
< 					tarx=zonesummon_x;
< 					tary=zonesummon_y;
< 					tarz=zonesummon_z;
---
> 					//zone debugging
> 					ZonePoint* zp = zone_point;										
1669,1673c1665,1673
< 					else if (zonesummon_x == -3 && zonesummon_y == -3 && (zonesummon_z == -3 || zonesummon_z == -30) && database.GetZoneName(m_pp.bind_zone_id)) {
< 						strcpy(target_zone, database.GetZoneName(m_pp.bind_zone_id));
< 						tarx = m_pp.bind_x;
< 						tary = m_pp.bind_y;
< 						tarz = m_pp.bind_z;
---
> 					else if (zonesummon_x == -3 && zonesummon_y == -3 && (zonesummon_z == -3 || zonesummon_z == -30)) {						
> 						if (database.GetZoneName(m_pp.bind_zone_id)){
> 							//zoneing to bind point
> 							strcpy(target_zone, database.GetZoneName(m_pp.bind_zone_id));
> 							tarx = m_pp.bind_x;
> 							tary = m_pp.bind_y;
> 							tarz = m_pp.bind_z;
> 							
> 						} //else bind point isn't set and we will zone to the zone safe point
1693c1693
< 						tarheading = zone_point->target_heading;
---
> 						tarheading = zone_point->target_heading;						
1696a1697
> 						
1699a1701
> 						
1704c1706
< 					else {
---
> 					else {						
1707,1709c1709,1711
< 						tarx=-1;
< 						tary=-1;
< 						tarz=-1;
---
> 						//tarx=-1;
> 						//tary=-1;
> 						//tarz=-1;
1719c1721
< 					if (target_zone[0] != 0 && admin >= minstatus && GetLevel() >= minlevel) {
---
> 					if (target_zone[0] != 0 && admin >= minstatus && GetLevel() >= minlevel) {						
1737c1739
< 						if (m_pp.zone_id == zone->GetZoneID()) {
---
> 						if (m_pp.zone_id == zone->GetZoneID()) {							
1749a1752,1753
> 							//zoneing to another zone so we need to the let the world server
> 							//handle things with the client for a while
1763,1764c1767,1768
< 					else {
< 						LogFile->write(EQEMuLog::Error, "Zone %i is not available", zc->zoneID);
---
> 					else {						
> 						LogFile->write(EQEMuLog::Error, "Zone %i is not available because target wasn't found or character insufficent level", zc->zoneID);
Feel free to critique...

Ves
Reply With Quote