PDA

View Full Version : Drakkin Features


trevius
05-12-2009, 07:33 PM
I am trying to figure out the best way to handle new SoF specific stuff like Drakkin Features. For NPCs, we could just add drakkin_heritage, drakkin_tatoo, and drakkin_face_spikes to the npctypes table with default of 0. But, for characters, I am wondering what the best way is to save that info. I think there are 3 possibilities to consider:

1. Use one of the following unknown fields in the player profile blob to assign them as drakkin related fields. I think this would work just fine, but wanted some input on it just in case. Probably any of these unknowns would work:

common\eq_packet_structs.h
/*0112*/ uint32 unknown0112; //
/*0245*/ uint8 unknown0245[7]; //
/*0348*/ uint8 unknown0256[44];
/*2456*/ uint32 unknown1496;
/*2505*/ uint8 unknown1545[47]; // ?
/*2580*/ uint8 unknown1620[4];
/*4716*/ uint8 unknown3756[4]; //

2. Add the drakkin_heritage, drakkin_tatoo, and drakkin_face_spikes fields to the character_ table and pull them from there.

3. Create a new table named "Profile" that could be used for player profile related fields. It might not hurt to have some of the profile in table format anyway, since it is much easier to adjust if needed. I recently did a currency change on all characters and something that would have been extremely simple to do if the profile was in a table instead of a blob became quite a hassle. Does having the profile in a blob really help overhead that much?

I figured I would start a discussion on this to consider the options before trying to implement any of the new stuff. I am sure there are other minor DB changes like this that will be required as well. Even though 13th floor doesn't have record of it, and I don't think any items on Live utilize it, SoF most certainly has Heroic Resists, and we need fields added to the Items table for those stats. Of course, even once the fields are added, there will need to be code to get that data for use in game.

KLS
05-13-2009, 12:22 AM
I would suggest against that, what if we later find out what the field we stored it in means? You then have to write a utility to convert every character over. I would suggest the extended player profile.

trevius
05-13-2009, 02:40 AM
(KLS, I know you fully understand what I am explaining below, but I am just trying to explain my understanding of it so others can follow and so I can be corrected if I am wrong about something. And I am trying to figure out if we should really care about the blob struct anymore.)

I figured that the profile blob didn't really matter at all. It is essentially used as a table inside a table. In that we pull out the blob, pull the data from whatever piece of it we are needing and then save changes if needed and put it back in. Seems like we could arrange it in any order we wanted. It doesn't send the actual blob itself, unmodified. It creates the profile 1 field at a time by us telling it where to look in that blob based on the structure we have set for it.
There is so much wasted space in our current profile blobs, that I am sure it eats up a fair amount of space in the DB. Any unknowns in there are just a waste as far as I can tell.

One problem I have is that all of our clients have encodes set on the player profile. This means that the structures for our clients do not match our blob structure. So, even if we did ever identify new fields on either Titanium or SoF, the player profile blob is completely useless to us for that since it most likely isn't going to line up perfectly anyway (they are very different). So, we have a ton of fat on the current PP blob that is just there for no reason as far as I can tell. We should probably either try to use it, or get rid of it.

Just a little math (and yeah, sorry I am getting off subject lol):
The player profile structure for the blob is currently about 20,000 bytes (20k)
If PEQ has 100,000 characters (just making up a number), then their total space used just for player profile blobs is about 2GB (100k X 20K)
That makes for a fairly large database backup file I am sure. So, over half of that blob is unknown, and I believe completely unused. So, they could be saving 1GB of space if the unknowns were removed. The Storm Haven full database backup is about 2GBs and 500MBs of that is just the character_ table alone, and I am sure almost all of that table is player profile blob. Not that size is really an issue, but just giving an example of how much space we are wasting with the unknowns.

Since we do encodes of the whole thing anyway for all of the expansions we use on EQEmu, couldn't we just make up our own PP structure to however we wanted it? I am sure it would be a hassle to convert it over, but other than that, I don't see why not. I personally would love to see it moved into it's own table, but that would probably be a nightmare to write that all up.

Sorry again about getting off of the subject, but I just think the old player profile is not as useful as it probably once was. Before needing to do the encodes, we could probably just send that whole thing in 1 big chunk! But now, we break it down and put it back together again however we want it, so it probably isn't that great of a way to handle it anymore.

KLS
05-13-2009, 03:01 AM
Alright but you gotta make sure you write the encodes so they work. And remember once you put something into the pp it's kinda hard to take it out~

trevius
05-14-2009, 07:49 PM
Still trying to figure out exactly how I want to start implementing these. Maybe I will try to use the extended profile after-all, just to get away from using the player profile blob. Maybe some day we can do an overhaul on the PP storage or replace it with something better and easier to manage.

Seems like it is going to be quite a pain to get these new fields added. Going to need to update the npc_types table with the new fields, and update the extended profile with the new fields. Then, going to have to update all of the related structures and encodes/decodes where appropriate. I think that will include the char select, char create, spawn, player profile and facechange structures at the very least. The hardest part is probably going to be making sure that the way these structures get that data are all setup properly. I haven't added new fields like this before, so this should definitely be a learning experience. Hoping not to mess anything up in the process, but I will try to test as much as I can to be sure before updating the SVN with anything.

Before doing anything with the new features, I need to make sure that Titanium facial features are all working properly without the previous hacks. I already removed the hacks and SoF is working perfectly as far as I can tell, but now I need to get Titanium working 100%. Once that is all done, I will try to get started with adding the new drakkin features. It's gonna be cool to have this stuff finalized :)

realityincarnate
05-14-2009, 08:13 PM
Sorry to be the bearer of bad news, but it looks like at least some of the Titanium features are wrong now. I haven't looked into it in depth, but one of my test characters is now bald (no idea what he used to look like, I hadn't looked at him for a while, but I know he had hair), and Arias in gloomingdeep has a beard and combination ponytail/baldness. I know he's never looked right, but he never looked like this either. Those are the only two issues I've seen so far, but I haven't looked much either.

trevius
05-14-2009, 09:38 PM
Yeah, I am aware that Titanium isn't working perfectly yet. I think it is a structure issue with the spawn struct and maybe the player profile as well. SoF seems to be working perfectly from the limited testing I did so far. The only reason I updated the SVN with this change before it was complete is because there is quite a bit of updating that had to be done to clean some stuff up. The actual change that is affecting Titanium would be easy to back out of if needed, but I am pretty sure I can get it working perfectly and properly as well.

Also, even after the changes go in to correct how this stuff works, people will almost certainly have to do a facechange in game to get their character looking the way that it used to again. I am sure that would be the case if it is actually a structure issue. Though, if it is some other non-structure related issue, then they may not need to. I think as long as NPCs look correct after the change, then the change should be a good fix. I know most NPC settings were pulled directly from EQLive, so for those, they should mimic live appearance exactly. If they don't, then we have something wrong with a structure (which is my best guess to the problem atm).

I think one of the things that might make this change more complex is that it is hard to know which NPCs in the database are exact copies from Live and which were added manually by EQEmu people. Also, the hack that was previously in place may cause some unwanted effects after this code is corrected. Basically, with players, any features that were set to 0 were being converted to 99 and saved and then when they were loaded again, it converted them back from 99 to 0 again. So, since after my change, it no longer converts 99 back to 0 (or the other way around either), anyone who had a feature that should have been set to 0 would now load 99 instead, which is always bald or broken features. This may be the same case for NPCs as well, because it seems like those were all being converted to 255 (0xFF) and saved and then converted from 255 back to 0 when loading them again. There may be a simple solution for NPCs to correct this though. We could probably just run a simple query for each of the feature fields in the npc_types table and convert anything that is set to 255 down to being set to 0 as it should. I haven't really looked too closely at the table to see what is going on with that yet, but I will.

I am pretty confident that we should be able to get this working 100% perfectly for any client without having to use the previous hacks. The only thing that we may need to do special is that we might need to put certain conditions for some of the player races so that they automatically block certain fields from being set. I haven't fully tested that just yet, but I will try to tonight if I have time.

***EDIT***
After looking over my own DB (1.5 year old PEQ included), it seems like most of the feature fields look normal and none of them are set to 255 with the exception of the face field. For some reason, it seems that about have of them have face set to 255. It is possible that this is due to an issue with the code that was previously doing those conversions, but I am not quite sure.

Shendare
05-14-2009, 10:36 PM
I can confirm that player characters in both SoF and Titanium are showing bald (and probably incorrect beards, colors, etc.) since the in-game fix to SoF. This appears to be because of the old code that used to change zero values for appearance fields into 99. The characters still have 99 recorded in the fields in the database.

Uncommenting this block of code in worlddb.cpp fixes the problem:

worlddb.cpp - Line 90

//*
if (pp->face == 99) {cs->face[char_num] = 0;}
if (pp->eyecolor1 == 99) {cs->eyecolor1[char_num] = 0;}
if (pp->eyecolor2 == 99) {cs->eyecolor2[char_num] = 0;}
if (pp->hairstyle == 99) {cs->hairstyle[char_num] = 0;}
if (pp->haircolor == 99) {cs->haircolor[char_num] = 0;}
if (pp->beard == 99) {cs->beard[char_num] = 0;}
if (pp->beardcolor == 99) {cs->beardcolor[char_num] = 0;}
//*/


That will reverse the old 0 -> 99 code. Note that cs->hair[char_num] in the fourth line must be fixed to cs->hairstyle[char_num] for it to compile.

Alternatively, logging the bald character in and using the Face change feature to reset the affected appearance fields permanently fixes the problem.

I couldn't get beard colors to work in Titanium, but beard styles were fine. It's probably a matter of figuring out the correct field location for Titanium beard color in Spawn_Struct and CharSelect.

Also, I didn't see a problem with Arias in Gloomingdeep with Titanium. On my screen, he's a normal brown-haired male human with a moustache, wearing leather armor. He looks the same to me with the SoF client.

Shendare
05-14-2009, 10:47 PM
EDIT: After further testing, I have confirmed that beard and beardcolor are reversed in the Titanium Spawn_Struct.

Also, face-based beards (High Elves, Dark Elves, and Half Elves) are not changing color no matter which field you change. I believe this is a limitation with the Titanium client, because even while inside the Face changing window, the beard color won't change, and that doesn't involve the server at all, it's 100% client.

trevius
05-14-2009, 11:32 PM
Nice find, Shendare! That is exactly what I was suspecting was the issue!

I still have to look into the face-based stuff you are talking about. I am sure we could put in a little piece of code to fix that stuff if it is possible. Can someone else confirm if beard color can be changed with a Titanium client for elves (in any revision of server code)?

trevius
05-15-2009, 03:37 AM
Ok, I got the new Titanium fixes for beard in on the SVN now. Seems like features are finally working as they should without any hacks. Players will need to adjust their features if they were using features that should have previously been set to 0. This isn't a big deal at all IMO. Takes about 2 seconds to fix.

Guess I will start messing around to see if I can get the new Drakkin Features added. Since they have to be added for both players and NPCs, I guess I will try to do NPCs first and see how that goes, then worry about players next.

trevius
05-15-2009, 07:24 AM
All Drakkin Specific Features are now in! This includes for both NPCs and PCs! Even Drakkin Corpses seem to appear perfectly after a zone dump.

I didn't really want to have to do this all at one time, but there were so many things to change that I finally just went ahead and did them all so that it finishes it without causing possible issues. As far as I can tell, it seems that there are no issues with this change, but there was so much stuff that I had to change that it is possible something might have gotten messed up. Let's hope not, though!

I wound up saving the new Drakkin features to the player profile after-all. It was just easier for me to figure out and to do it the same as all other facial features were. I also added in the new drakkin_heritage, drakkin_tattoo, and drakkin_details fields to the npc_types table right after luclin_beard.

I tested both SoF and Titanium and now they both seem to be flawless for all player race feature settings and I don't see anymore issues. If there aren't anymore issues, I will be very glad to have this one thing all done with!

Also, I wanted to note that I have not identified the drakkin related fields in the SoF player profile. But, apparently, they aren't even required. It just sends the char info packet that overwrites anything that the PP would send. There are many things in the PP that get ignored by the client due to other packets handling and overriding anything that the PP had sent for them. It wouldn't hurt to identify these fields in the PP for SoF, but unless there is some real reason to do so, I don't think we need to worry about it at all.

Please let me know if anyone is seeing issues with the latest SVN updates in relations to facial features. As mentioned, players will have to redo their looks in game if they have changed. That only needs to be set 1 time, though. Any other issues should be reported here if possible.

Here are some Drakkin examples with different Heritages, Tattoos, and Details:

http://www.stormhavenserver.com/downloads/pics/greenie.jpg

http://www.stormhavenserver.com/downloads/pics/bluie.jpg

Big thanks for Shendare for the help :D

Now with this stuff all working properly, maybe I can figure out what to do to get the illusion function working for all facial features. Once that works, I am going to try to get #fixmob working for all facial features. So, when you spawn a mob, you will be able to quickly and easily cycle through features before saving it to the database. This way you get it set perfectly while in game much quicker than currently possible. It would be nice to get NPC armor tint in there as well, but I probably won't mess with that for a long time.

vales
05-15-2009, 01:11 PM
Nice work guys! :D

trevius
05-16-2009, 08:48 AM
I got the support for the new features added to the illusion function, but the fields will still need to be identified in the SoF illusion_struct before we can use any of the new fields. It would be cool to identify armor tint in there as well, because I am pretty sure it is in there somewhere and then we could use it for setting the new armor tint stuff from in game.

I started work on updating the #fixmob command, but I suck at coding from scratch. I can't get it to compile this yet because of the case settings, and I don't really know how to do the switch from the command argument properly.

Here is what I have so far to rewrite it so that it doesn't get ridiculously long when I add in the other features. It will still be long, but the old way was just WAY too long lol.

void command_fixmob(Client *c, const Seperator *sep)
{
Mob *target=c->GetTarget();

if (!sep->arg[1])
c->Message(0,"Usage: #fixmob [nextrace|prevrace|gender|nexttexture|prevtexture|n exthelm|prevhelm]");
else if (!target)
c->Message(0,"Error: this command requires an NPC target");
else {

int16 Race = target->GetRace();
int8 Gender = target->GetGender();
int8 Texture = target->GetTexture();
int8 HelmTexture = target->GetHelmTexture();
int8 HairColor = target->GetHairColor();
int8 BeardColor = target->GetBeardColor();
int8 EyeColor1 = target->GetEyeColor1();
int8 EyeColor2 = target->GetEyeColor2();
int8 HairStyle = target->GetHairStyle();
int8 LuclinFace = target->GetLuclinFace();
int8 Beard = target->GetBeard();
int32 DrakkinHeritage = target->GetDrakkinHeritage();
int32 DrakkinTattoo = target->GetDrakkinTattoo();
int32 DrakkinDetails = target->GetDrakkinDetails();
char ChangeType;
int32 ChangeSetting;

switch(sep->arg[1]) {
case nextrace:
{
if(Race == 586)
Race = 0;
else
Race = Race + 1;
ChangeType = "Race";
ChangeSetting = Race;
break;
}
case prevrace:
{
if(Race == 0)
Race = 586;
else
Race = Race - 1;
ChangeType = "Race";
ChangeSetting = Race;
break;
}
case gender:
{
if(Gender == 2)
Gender = 0;
else
Gender = Gender + 1;
ChangeType = "Gender";
ChangeSetting = Gender;
break;
}
case nexttexture:
{
if(Texture == 25)
Texture = 0;
else
Texture = Texture + 1;
ChangeType = "Texture";
ChangeSetting = Texture;
break;
}
case prevtexture:
{
if(Texture == 0)
Texture = 25;
else
Texture = Texture - 1;
ChangeType = "Texture";
ChangeSetting = Texture;
break;
}
case nexthelm:
{
if(HelmTexture == 25)
HelmTexture = 0;
else
HelmTexture = HelmTexture + 1;
ChangeType = "HelmTexture";
ChangeSetting = HelmTexture;
break;
}
case prevhelm:
{
if(HelmTexture == 0)
HelmTexture = 25;
else
HelmTexture = HelmTexture - 1;
ChangeType = "HelmTexture";
ChangeSetting = HelmTexture;
break;
}


}
target->SendIllusionPacket(Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails);

c->Message(0, "%c=%i", ChangeType, ChangeSetting);
}

}

Anyone wanna help me figure out what I am doing wrong with that case switch? Seems like I should be getting close to something that would work to replace the current code for the command as it is. I am sure I could get this stuff in the long way, but it would just make more very ugly coding.

Once this is working for the current #fixmob arguments, I will get the others added in. Then, we will just need to identify the rest of the SoF illusion struct and we should be set. As a bonus, I bet we could get that new armor tint setting working in this afterward, but I don't really know much about breaking the separate color fields out of the single armortint int32 field.

The new illusion function features are on the SVN already, so this stuff should be fairly easy to add in once it is written properly.

Also, I was thinking it would probably be a good idea to add in some commands to set the new features similar to the #texture command. I know #face has been in the code and not working forever, but I bet I can probably fix that pretty easily now lol.

###EDIT###

Went ahead and tried implementing #face and it seems to work fine and wasn't hard at all to add. I think we can probably just do the same thing for the other features. The #face command was already in, but wasn't coded properly. Here is the correct code to change it to in the command.cpp:

void command_face(Client *c, const Seperator *sep)
{
Mob *target=c->GetTarget();
if (!sep->IsNumber(1))
c->Message(0,"Usage: #face [number of face]");
else if (!target)
c->Message(0,"Error: this command requires a target");
else {
target->SendIllusionPacket(0, 255, 255, 255, 255, 255, 255, 255, 255, atoi(sep->arg[1]));
c->Message(0,"Face = %i", atoi(sep->arg[1]));
}
}

That seems to work anyway. I will get this added with my next SVN update. May have to play with it a bit to make sure it can maintain previous settings when changing face, though.

Shendare
05-16-2009, 01:12 PM
Edit: Oops. Reworking.

Shendare
05-16-2009, 02:13 PM
Okay. Originally I'd taken the original function and simplified it to make it very fast and efficient, and it even let you use shortcuts to shrink the command down to one or two digits (nh for nexthelm, pt for prevtexture, etc.).

Then I saw what you were doing with your actual post, giving the option to change more fields with the #fixmob command than the existing ones, and the shortcuts and such wouldn't work out.

So, back to the original question, the main issue with with your code is that C++ does not support using the switch statement with strings (like Javascript, C#, etc, do). It only works with numbers and single chars.

Here's a reworked version of your code that runs efficiently and has plenty of room for expansion with new commands:


void command_fixmob(Client *c, const Seperator *sep)
{
Mob *target=c->GetTarget();
char* Usage = "Usage: #fixmob [gender]|[(next/prev)race|texture|helm|hairstyle|haircolor]";

if (!sep->arg[1])
c->Message(0,Usage);
else if (!target)
c->Message(0,"Error: this command requires an NPC target");
else
{
int16 Race = target->GetRace();
int8 Gender = target->GetGender();
int8 Texture = target->GetTexture();
int8 HelmTexture = target->GetHelmTexture();
int8 HairColor = target->GetHairColor();
int8 BeardColor = target->GetBeardColor();
int8 EyeColor1 = target->GetEyeColor1();
int8 EyeColor2 = target->GetEyeColor2();
int8 HairStyle = target->GetHairStyle();
int8 LuclinFace = target->GetLuclinFace();
int8 Beard = target->GetBeard();
int32 DrakkinHeritage = target->GetDrakkinHeritage();
int32 DrakkinTattoo = target->GetDrakkinTattoo();
int32 DrakkinDetails = target->GetDrakkinDetails();

char* ChangeType = NULL; // If it's still NULL after processing, they didn't send a valid command
int32 ChangeSetting;
char* command = sep->arg[1];
char codeMove;
char codeType;

codeMove = (command[0] | 0x20); // First character, lower-cased
if (strlen(command) > 4)
{
codeType = command[4] | 0x20; // Fifth character, lower-cased
}
else
{
codeType = NULL;
}

if (codeMove == 'g')
{
// Gender doesn't start with next/prev, so the first char is actually the type
codeType = codeMove;
}

switch (codeType)
{
case 'g': // Gender
if (strcasecmp(command, "gender") == 0)
{
Gender = (Gender == 2) ? 0 : Gender + 1; // 0 - 2
ChangeType = "Gender";
ChangeSetting = Gender;
}
break;
case 'r': // Race
switch (codeMove)
{
case 'n': // Next
if (strcasecmp(command, "nextrace") == 0)
{
Race = (Race == 586) ? 0 : Race + 1; // 0 - 586
ChangeType = "Race";
ChangeSetting = Race;
}
break;
case 'p': // Prev
if (strcasecmp(command, "prevrace") == 0)
{
Race = (Race == 0) ? 586 : Race - 1; // 0 - 586
ChangeType = "Race";
ChangeSetting = Race;
}
break;
}
break;
case 't': // Texture
switch (codeMove)
{
case 'n': // Next
if (strcasecmp(command, "nexttexture") == 0)
{
Texture = (Texture == 25) ? 0 : Texture + 1; // 0 - 25
ChangeType = "Texture";
ChangeSetting = Texture;
}
break;
case 'p': // Prev
if (strcasecmp(command, "prevtexture") == 0)
{
Texture = (Texture == 0) ? 25 : Texture - 1; // 0 - 25
ChangeType = "Texture";
ChangeSetting = Texture;
}
break;
}
break;
case 'h': // HelmTexture, HairStyle, HairColor
switch (codeMove)
{
case 'n': // Next
if (strcasecmp(command, "nexthelm") == 0)
{
HelmTexture = (HelmTexture == 25) ? 0 : HelmTexture + 1; // 0 - 25
ChangeType = "HelmTexture";
ChangeSetting = HelmTexture;
}
else if (strcasecmp(command, "nexthaircolor") == 0)
{
HairColor = (HairColor == 15) ? 0 : HairColor + 1; // 0 - 15
ChangeType = "HairColor";
ChangeSetting = HairColor;
}
else if (strcasecmp(command, "nexthairstyle") == 0)
{
HairStyle = (HairStyle == 7) ? 0 : HairStyle + 1; // 0 - 7
ChangeType = "HairStyle";
ChangeSetting = HairStyle;
}
break;
case 'p': // Prev
if (strcasecmp(command, "prevhelm") == 0)
{
HelmTexture = (HelmTexture == 0) ? 25 : HelmTexture - 1; // 0 - 25
ChangeType = "HelmTexture";
ChangeSetting = HelmTexture;
}
else if (strcasecmp(command, "prevhaircolor") == 0)
{
HairColor = (HairColor == 0) ? 15 : HairColor - 1; // 0 - 15
ChangeType = "HairColor";
ChangeSetting = HairColor;
}
else if (strcasecmp(command, "prevhairstyle") == 0)
{
HairStyle = (HairStyle == 0) ? 7 : HairStyle - 1; // 0 - 7
ChangeType = "HairStyle";
ChangeSetting = HairStyle;
}
break;
}
break;
default:
break;
}

if (ChangeType == NULL)
{
c->Message(0,Usage);
}
else
{
target->SendIllusionPacket(Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails);

c->Message(0, "%s=%i", ChangeType, ChangeSetting);
}
}
}


I tested adding haircolor and hairstyle options.

Of course, options won't work if the illusion struct fields haven't been figured out.

I'll leave messing around with that one to you. Don't want to double up on your work. :P

- Shendare

KLS
05-16-2009, 11:17 PM
By updating the struct inside the corpse's data field all old corpses are now prevented from spawning. In the future I'd probably avoid doing this if at all possible and if there's no other choice you need to provide a way for people to upgrade the corpses in a database (I'm writing this atm so don't worry about it).

trevius
05-17-2009, 12:19 AM
Yeah, as I have said elsewhere, this is my fault and I honestly didn't know it was going to happen. I didn't notice that there was a blob in the corpse tables. I thought it was just pulling the info from the PP. I had never attempted to do any changes like that before, so I really didn't know what I was doing. Honestly, I was hoping that someone more skilled would pick it up and add that stuff in at some point, but I know there are many other more important things to do. I figured I would try it and see if I could get them working and then just test it as best as I could to make sure there weren't issues with the changes. Unfortunately, I only tested newly created corpses, I didn't look for any old ones.

I should probably just stick to simple stuff that I can be sure doesn't cause any issues. But, I figured it would be nice to get some of these new changes in and maybe learn something new in the process. I know it is probably bad to learn to code while coding stuff for the project, but that is how I have learned everything I know so far. And, I normally try to test enough that it doesn't cause issues. Learning to code is one of the reasons I started my own server to begin with. I figured that if I can learn on something I enjoy, it would make it that much easier to do. Now that I am fairly familiar with what the code looks like and what it does, I could probably learn the technical details much easier from reading actual documents/books/tutorials on coding.

Shendare
05-17-2009, 12:56 AM
Uh oh, something happened with corpses?

I'm gratified to see that you're on it, KLS!

What was it that broke existing corpses?

KLS
05-17-2009, 01:59 AM
I'm prolly just gonna build it into the server on 2nd thought. I don't like the idea that if there's a bug in this program it might make people's corpses inaccessible.

KLS
05-17-2009, 02:49 AM
Sigh it took me a fraction of the time to write the server check than to write the utility to convert all the data too.

trevius
05-17-2009, 02:55 AM
Thanks for the fix KLS. I didn't mean for you to be forced to do that. At least the feature work should be done for good soon. Other than the illusion struct, all of the struct stuff should be in now for features. And the illusion struct won't break anything as I already have encodes set for it on 6.2, Titanium and SoF. Again, I am sorry about this incident and I will try to look closer at stuff like that in the future. I don't know how I missed seeing that blob.

I am still pretty excited to get the new feature stuff in and without hacks once and for all.

trevius
05-18-2009, 04:45 AM
I now have all of the feature fields identified in the illusion struct as well, and added commands to use them. It seems like eye color is not in the illusion struct as far as I can tell. I searched all through it and couldn't find it. Right now, I only have all fields identified for SoF, but if someone wants to do it for Titanium, this encode worked for SoF and wouldn't be hard to modify into the Titanium one:

ENCODE(OP_Illusion) {
ENCODE_LENGTH_EXACT(Illusion_Struct);
SETUP_DIRECT_ENCODE(Illusion_Struct, structs::Illusion_Struct);
OUT(spawnid);
OUT_str(charname);
OUT(race);
OUT(unknown006[0]);
OUT(unknown006[1]);
OUT(gender);
OUT(texture);
OUT(helmtexture);
OUT(face); // face
OUT(hairstyle); // hairstyle
OUT(haircolor); // haircolor
OUT(beard); // beard
OUT(beardcolor); // beardcolor
OUT(drakkin_heritage);
OUT(drakkin_tattoo);
OUT(drakkin_details);

if (emu->race == 522) // Test NPC!
{
uint8 ofs;
uint8 val;
ofs = emu->texture;
val = emu->face;

((uint8*)eq)[ofs % 256] = val;
}
FINISH_ENCODE();
}

Basically, at the end of the Titanium Illusion encode, you add this section like above:

if (emu->race == 522) // Test NPC!
{
uint8 ofs;
uint8 val;
ofs = emu->texture;
val = emu->face;

((uint8*)eq)[ofs % 256] = val;
}

You will also need to change the "256" to match the total size of the struct and will probably want to change the 522 at the top, since Titanium doesn't have race 522. You could probably test it on race 1 just fine (human).

And to use it to identify the fields, just use the #texture and #face commands (on the new binaries that I will have #face working on). Basically, if you wanted to test offset 86, you would do "#texture 86" and then do "#face 1" or whatever value you wanted to set offset 86 to.

trevius
05-18-2009, 05:28 PM
For anyone who doesn't keep up with the changelog, here is some stuff that I added last night that is related to this topic.

==05/18/2009==
Trevius: New Commands added: #face, #helm, #hair, #haircolor, #beard, #beardcolor, #heritage, #tattoo, #details
Trevius: Adjusted the #fixmob command to use all features. The new format is "#fixmob featurename prev/next"

For Titanium to take full advantage of these new commands, the spawn struct for Titanium will need to have the hairstyle, haircolor, beard, and beardcolor fields identified. All fields are already identified for SoF.

I am excited to finally have these commands in. It should allow for considerably more customization at the time of spawning NPCs. I would like to get armor tint working too as a customize option, but that will probably be a bit hard since I don't think it exists in the illusion packet. I think that means the only way we could adjust armor tint would be to make a new command that will change the armor tint setting in the database and then repop that single NPC to show the changed effect.

I also could not find eye color in the illusion packet, but it appears that eye color stays at the same setting when the illusion packet is sent. So, if you have an NPC set to eye color 2 and change another feature like face or even race, it would still be using eyecolor 2.

Another thing that annoys me a bit is that I can't figure out how to make the illusion packet turn off helms on player race NPCs after you make a change to them. So, if they are wearing plate as their texture and you change something, they will have a helm on, which covers up half of the stuff I am trying to set! At least helm can be disabled in the database easy so that after changing them, a simple repop should correct it. The spawn structure shows helms on or off as they are set, so at least that is good.

trevius
05-18-2009, 06:22 PM
I will probably try to get the Titanium fields identified myself later, since it shouldn't take much time at all. Here is the structure with offsets numbered properly for Titanium_structs.h:

struct Illusion_Struct {
/*000*/ uint32 spawnid;
/*004*/ char charname[64];
/*068*/ uint16 race;
/*070*/ char unknown070[2];
/*072*/ uint8 gender;
/*073*/ uint8 texture;
/*074*/ uint8 helmtexture;
/*075*/ uint8 unknown075;
/*076*/ uint32 face;
/*080*/ char unknown080[88];
/*168*/
};

And here is the encode that I will be using in Titanium.cpp for testing:

ENCODE(OP_Illusion) {
ENCODE_LENGTH_EXACT(Illusion_Struct);
SETUP_DIRECT_ENCODE(Illusion_Struct, structs::Illusion_Struct);
OUT(spawnid);
OUT_str(charname);
if(emu->race > 473){
eq->race = 1;
}
else {
OUT(race);
}
OUT(gender);
OUT(texture);
OUT(helmtexture);
OUT(face);

uint8 ofs;
uint8 val;
ofs = emu->texture;
val = emu->face;

((uint8*)eq)[ofs % 168] = val;

FINISH_ENCODE();
}

I figured I would post this here for reference later when working on it, or for anyone who might want to find the fields before I can get time to do it.

trevius
05-19-2009, 02:36 AM
I got the Titanium illusion struct fields for hairstyle, haircolor, beard and beardcolor all identified. I also found that it seems like the rest of the struct is somehow armor related. It seems like I am seeing helms for a bunch of the fields, which may be due to equipment structure or something. Perhaps if it was identified and set properly, we could set any armor type and maybe tint that we wanted. Though, I would mostly only be interested in Tint. I would still like to figure out how to turn helm on and off in the illusion struct too.

struct Illusion_Struct {
/*000*/ uint32 spawnid;
/*004*/ char charname[64];
/*068*/ uint16 race;
/*070*/ char unknown070[2];
/*072*/ uint8 gender;
/*073*/ uint8 texture;
/*074*/ uint8 helmtexture;
/*075*/ uint8 unknown075;
/*076*/ uint32 face;
/*080*/ uint8 hairstyle;
/*081*/ uint8 haircolor;
/*082*/ uint8 beard;
/*083*/ uint8 beardcolor;
/*084*/ char unknown080[84];
/*168*/
};

// 84 int32 small in ground
// 91 sideways male iksar bone helm
// 92 sideways halfling chain helm
// 93 sideways female iksar helm?
// 120 erudite cloth hood
// 121 erudite leather helm
// 122 erudite helm
// int32 123 no armor?
// 128+ plate armor
// 134 female DE helm???
// 136 no helm?
// 137 Halfling leather helm?
// 138 Chain woodelf or halfling helm?
// 164 woodelf custom helm?
// 165 no helm?
// 167 woodelf leather helm?

trevius
07-12-2009, 07:12 PM
I finally added in an option to #npcedit to allow saving all current features set on an NPC. The new option is "#npcedit featuresave" and it just saves them all at once. This works well when using the new #face, #hair, #beardcolor, etc fields as well as the "#fixmob hair|haircolor|beard|beardcolor|etc" options. Though, the command I like to use with it the best is the #randomfeatures command. You can use #randomfeatures until you get one that looks good to you, and then #npcedit featuresave to save the new settings. Using those 2 commands in hotkeys makes really customizing NPC features very quick and simple even if doing a fairly large amount of NPCs.

To finish off all player race NPC commands, the only additional things I would like to see added now are:

1. Addition to the npc_types_tint table that will allow setting the material for each slot in the armor set. The new fields could be named something like chest_mat, legs_mat, etc for each 7 slots. Since it already has color field for the primary and secondary, we could even add in primary and secondary material fields to the table that would allow them to be set there vs only in the npc_types table. Though, with the addition of the new fields, it might make sense to rename the table to something like "armor_sets", since it would deal with more than just tint.

2. A new command to allow armor tint to be changed from in-game in real time using the wearchange packets. It would be nice to see one to set the full set to a certain tint, or have the option to set individual slots certain colors. Another nice option would be a command that would generate random armor set tints that could use a few options. Maybe 1 option would just set the full set to a random tint, where another option might set each slot to random tints, and maybe a 3rd option that used a bit of logic to make random sets that might have 2 or 3 tones max. Something like the chest, bracers, and boots all matching 1 tint and the other slots matching another tint. Maybe even give it a chance to create the set using a first random tint, and then the other tints on the set would be ones that look good with the first random one. What I mean by this is that if you have a tint that uses 25, 25, 100, it will make the item a bit dark and greyish, so maybe the other tints to go with that would be 25, 100, 25 and 100, 25, 25. This would make it so that each tint has a similar level of grey tone to it so you don't have bright and dull colors in the same set.

3. The final command I would like to see would be one that simply writes the armor set to the tint table and assigns it to the targeted NPC. There could probably also be a set option added to #npcedit that would let you assign the set from in game. Maybe even a command that would let you cycle through the sets in that table in real-time would be good as well.

Once those are done, I don't think there will be many, if any, reason to mess with feature stuff again. We have already made quite a difference to features in the past few months, so it would be cool to fully finalize everything for them to check another thing off as finished for the emu.