27. Juli 2010
I found a few, for example an opcode sent by the client when he receives a new spawn (player) with an unknown guild id. Normally all guilds and their ids are sent upon zoning, but if a new guild is created meanwhile the client does not know anything about the guild (name etc).
I also found a client command i had forgotten about or never used anyway, the /channel command. Apart from the server side filter command this command enables you to turn off the specific chat channels like gsay,ooc,auction,shout,ooc etc. The client can inform the server that he wants to either turn on/off a channel. I identified the requests from the client, we only need to add the filtering to the server which shouldn't be hard.
= 10020min (167h)
26. Juli 2010
Basically, this means we have a base line of defence now for easy file hacking.
= 9780min (163h)
20. Juli 2010
Additionally, i also extended the trigger and traps framework to be able to spawn a random amount of npcs at a specific location (i.e. beetles in necropolis for example).
Finally i've spent alot of time of preparing a video, which is not easy todo because you can die pretty fast from a train triggered from these traps =)
= 9180min (153h)
13. Juli 2010
The first spawn based trap i added was the one for frozen tower, when you enter the zone just to the left 3 shadowbones will spawn. There are more zones with triggers like this, necropolis and runnyeye comes to my mind, im not aware of any other currently.
I also worked on the spell effects a trap executes, i had issues getting the spell effects visible to the client, after a bit of debugging i found out that the invisible npcs where not sent to the client, and when you want to see a spell effect you supply a caster ID of the mob who casts the spell. If the client doesnt know this id, you will obviously see no effect.
I hope i can make a video this week about triggers, since i will be gone for a short vacation for the rest of the week.
= 8700min (145h)
9. Juli 2010
I fixed some doors in necropolis and pendulum traps, and added the missing qeynos doors to a delta sql. Then i create a db table for triggers with different attributes and integrated it into the base code. Triggers can now be easily assigned to "hidden" npcs. They can either cast spells, summon X mobs or just print a message. Then i made certain that mobs or players cannot attack triggers.
I also added the 15 different traps for necropolis including their spells and trigger messages. I started with exploring EQ Live again and started gathering all the environment messages i have the location of: chardok, frozenshadows, kael, runneye, westwaste. I checked some other zones i had some info on but they did not have (anymore?) the messages. There are a few kunark/velious zones left i have to check.
= 7500min (125h)
7. Juli 2010
= 6720min (112h)
6. Juli 2010
In the next days i will add spell/message support to these and finally need to put my collected data into a database table, i.e. trap ID x, do spell Y when client is near proximity Z and say a specific message. Additionally i need to add a disarm check to these so they dont trigger when a rogue/bard disarmed a trap temporary.
= 6180min (103h)
4. Juli 2010
However even with this info i triggered a trap more often then not, sense traps is very hard on live now. I started with 1 skill on this rogue and its now at 60, even when i sense traps 3 times before each spot - there is a high chance i miss the trap. These are the reasons for death mostly, also since i need to trigger the trap anyway to know what it does it sometimes means also death. Disarm on some of these traps is a pain, at first i thought its a range issue, but it wasnt, i literally took up 20 tries to disarm some specific traps here even with a skill of 60 disarm traps. Talk about wasted times since these skills are on a cooldown of about 10sec.
Since the chance to find the last 2 traps is less then 10% i will stop here and use a similar effect i see fit, maybe somebody else i bored and will do this, but i have enough of necropolis =).
After that i went velks lab, thankfully there are only 2 different traps here which i found easily using above method.
Finally i went to chardok and found the different traps on the bridges and the text/effects.
There are one or two traps in the frozen tower which doesnt seem to do any damage, which will also be added.
So, this is it - as you can see about 24h went just into researching this stuff without any line of coding done =/.
= 5700min (95h)
2. Juli 2010
= 4980min (83h)
1. Juli 2010
= 4620min (77h)
28. Juni 2010
I also found that the client had a check when you got near a trap, it removes any invisibility spell - the funny thing is, this only triggers when im standing at very specific locations at a trap. This initially let me believe that there must be some kind of radius i need to set how big the area should be the trap effects, but it was still hopeless =/.
Anyway, i finished the sense trap skill and the disarm trap skill. There are two possibilities to use the disarm trap skill - either click like mad on the trap itself, or use the disarm trap skill button, on the server the nearest trap will be located and then it will be tried to be disarmed. Once a trap is disarmed, it will stop for about a minute and you will not "sense" it anymore since it is disarmed, you will sense another trap if any is nearby, same applies for disarm.
Currently whats missing is obviously that no damage is generated from traps, i had to do that server side anyway for the kunark/velious traps which were just invisible mobs which triggered on proximity instead of "on hit" like the few dozens classic traps in SolA+B and paw.
Instead of 99%, i am now 99.99% certain that there is no damage trigger client side and it was all generated server side back in the days.
= 4380min (73h)
25. Juni 2010
I also figured out the disarm trap skill so far, it seems there are two possibilities here - a rogue with at least 1 in disarm trap skill can click on a trap OR just use the skill disarm traps to execute the disarm action. In the first case it is similar handled to opening a door (client sents to the server a request with the door/trap ID), in the latter case its just the info that the client wants to use the disarm trap skill without any associated trap. The clicking on the trap is rather easy at first, but you had to figure out what to sent back that the trap visually stops moving. Its another value in the open/close door action which we already use for closing/opening doors on the client.
So visually disarm trap for clicking a trap works, i need to do some server side code for using the skill button to figure out which is the nearest trap next to the player, same goes for sense traps. This is the easy part.
However, i spent most of my time debugging the client and figure out why no damage is generated from traps when you walk into them. The damage should be done client side i think, its the same with drowning or falling in lava - the client recognizes this event and will do damage locally and only sent the info (and the damage done) to the server. I went as far as logging into EQL and going to SolusekA to take a look how the traps work, the damage of each trap was hardcoded and always the same for each different type. What is funny is that using the damage value information i was able to find the client side function, which returns a different trap damage value depending on the trap type (pendulum, spears, saw). I spent most of my time reversing were this function is called from - but there was no indication that the client would do a check if the player is near a trap - damage him.
I will spent some more time reversing the client and trying to find out why the trap doesnt do damage, might be still a specific byte in the door/trap struct we sent to the client to spawn these door/traps - who knows. I currently think that the older client didnt trigger the damage, it was done server side and later changed to be client side - it would be easy to do this on the server (similar to sense traps, if a client gets near a trap the server would damage him). However it would have the visually effect of doing damage to the client, even when the pendulum is currently not hitting the client since the animation is done by the client the server cannot possibly know when it would hit the player, it can only know that the client is standing where a trap is.
When you think about it, that there are only 20 real traps in classic in 3 dungeons (soluseka,b and paw) - thats alot of engineering going into such a small part of the game =).
= 3540min (59h)
23. Juni 2010
I additionally added the last missing things for range attack, rogues deadly strike, i guess range attack should be done for now. Also some refactoring on some ugly code like melee kick attack. Warriors at or above lvl55 now have a chance to stun their target when kicking.
= 2880min (48h)
21. Juni 2010
I wanted to check some things out in kedges keep and teleported there, of course i forgot to cast an enduring breath spell - but that wasnt the major issue. As soon as i zoned into underwater i started to drown, which should normally not happend because you got an air bar as soon as you dive into water.
Well i figured that how much air the player has left has not been identified in the playerprofile, so we probably always sent 0 when the player zones. I searched with the debugger in the client to identify the function, where the "air is left" check is done. At first i thought i was quick finding it, i set the value to 255(0xff) server side and tried to relogin while being underwater, but it didnt help - i started to drown again. Confused i tried some other unknown fields we had - same result. A few hours later i figured, on the client there was another function to sanitize the air left value while checking - 255 wasnt a good value. So i started with the first field in the playerprofile i thought i had found. I set it to 10, and zoned in - i didnt start to drown immediately but the air left window at least popped up and was almost zero. After a saw that the client had 2 max values for this field - it was either 100 or 127 for iksars (they can hold their breath pretty long =). So after this field was identified, i could save it when the client requests a save - and the next time the client zones it will take the last saved value. So, you should drown instantly as soon as you dive from qeynos to qcat =). The time on this field is approx in seconds, it seems the client generates this value out of the endurance/stamina the client has. So normally a client can dive over one minute, or iksar over 2 before the air runs out - pretty long i must say, didnt remember that. Fun fact: the client substracts 0.125 * YourHP every drowning interval, so you are pretty much dead after 8 intervals, no matter how much HP you have left.
Next i added the broadcasting of tradeskill combine/failures to the group, as it was classic as pointed out in the forum - the part was already there when i reworked tradeskills last year but i left it outcommented because i wasnt sure it was classic.
Finally, i added a new gm method #listentities to view all the npcs that are currently spawned in the zone along with XYZ. Along with this its easy to use /goto a_mob_00 to teleport to him.
18. Juni 2010
I checked the loading code from the database and it seemed fine, i didnt understand why the bagSize was always 0.... well after a while it turns out it was a really stupid mistake. I was always fixing the race/class bitmask (see earlier posting) at the very end of the loading code for each item. Well, however these fields in the item struct are only used by "normal" items, not by books or bags. When you set the race data in the struct, you effectivly overwritting the bagSize property cause they are both at similar position in the itemstruct bytewise. So it went like this: load item from DB -> ok its a bag -> set bag attributes -> do stuff -> finally set race/class bits == same position in struct as bag attributes -> overwrite these values again (with 0 in this case = 0 = tiny bag size).
It must have been a design decision by verant very early to missuse the same struct position of an item depending on the item type - to save some network traffic i guess.
As far as summoning items is concerned i only found one spell which really have a level based code for the amount of charges returned -> summon bandages (level/2) - any other spell would always return the max value regardless of level (20 arrows/daggers/food/drink for Cornucopia and co).
17. Juni 2010
I started to search for items, where the idfile attribute in the item differs. After about an hour and more then 15 different idfile mappings i came to the conclusion that proceeding a manual mapping for each item would be an insane job, which no real programmer would do =).
So i wrote a program which compares each item from the blob and non blob table, and takes the idfile information from the old table. When an item is not found in the blob table but in the newer one, i used the idfile of a similar item which had a similar new_idfile->old_idfile mapping. The program procued an SQL delta update file which sets the idfile for all items which existed in the blob table. This way we should have a relatively complete item table but with the correct idfile mappings of older clients.
I verified alot of things i could think of with the new item information
- check item description
i havent found an issue, the client doesnt complain. There should be no issues for new characters, but maybe some items are missing for existing ones, therefor before i do a commit i let YL test it on his chars if everything works out.
I also toyed around with the loginserver, i did not try it out yet. I got it to compile quite easily thanks to neorabs description txt. For developing, we just skip the loginserver and connect directly to our local server, you are directly transfered to char selection instead of going to the server select.
Was funny to see the old interface, i clicked on Create Account and remember the screen where you needed to put in your CD key, name, address etc to get your account approved. There wasnt a webpage to register in classic, everything was done using the client.
16. Juni 2010
The first issues i had where the number of items, newer item table dumps contain alot of items (which we will not use), and the eqclient only supports 16bit integer MAX number of items. The item # in the item struct is just 16bit, since i forgot about that i was seeing all sorts of weired things happening when i logged into the zone, corpses had 20 items on them which looked like gloves, my equipment vanished mostly, i was getting alot of "bogus item received, item deleted" messages from the client. The glove item was in the item table exactly at # 16bit int max, so it overwrote the array each time =).
The next thing with the bogus items was, the race and class bits on each item. EQ uses a bitmask to know which class/race can use an item, each class/race represents one bit like 0001, another class is 0010, now when you have 1111 it means all class/races can equip this item. So, the issue here was that the newer item table dumps included a higher bitmask for all classes/races - because in the years more classes and races have been added, so i just needed to remove the higher bits. That means the items use a bitmask of 11111111 11111111 - but the client only knows up to
01111111 11111111 for classes, and 00011111 11111111 for races. After this fix, you wouldnt get any messages about bogus items any more.
Now i tried a few things, like shopping, dropping, trading etc the newer item tables
seems to work fine so far, i only found one issue - some bows do not show a graphic when you equip them. The item struct contains like over 100 attributes, and only a few bits are still unknown to us, these seem to have a meaning and are causing this issue.
I didnt know that there where range items with a proc, but since i was testing bow damage i found one of the top bows from a PoA quest - windstiker which has a cool proc effect Whirlwind. The mob spins around itself like M.J. dance. Turns out there wasnt any code for handling proc damage from a range item, which i therefor added.
As i was equipping my ranger with some nice tolans gear, i saw that they all had nice spell effects. The bracers had summon arrows, i tried it out and for the long casting time it had - only one arrow came out. That couldn't be right so i tried some mage spells which summon 20 charges of food - the same issue, only one item. Turns out that the max charge info was not honored in the spell code for summon items, i fixed that and the correct amount should be summoned now (the information is found i nthe spdat spell info and seems to be correct, i checked summon bandages which should summon 5 bandages and all other mage spells, seemed fine).
8. Juni 2010
Anyway, in my reverse engineering i figured that the client has 2 different checks for the recast delay, one is executed for the velious fullscreen ui, one for the classic UI (it can drive you insane when you just found a breakpoint, but for no reason it doesnt work the next time you start the eqclient). The check points to some memory location depending on the spell gem number, if the value is 4, the spell is on a cooldown. Well, now the issue is i havent found where this value is set - there must be a separate thread which countdown the recast delay and set this.
So finally, i came to the conclusion that it mostly aint an error in the playerprofile, why?
When you set the value in the profile, which is loaded once you zone in, the spell gems are greyed out the second you are logged in, except for the first one. There is a similar client side mechanism when you cast a spell - the client knows what the recast timer the spell has. So i did a small test finally, I cast a spell with a recast of 12sec, like bind affinity - on the first gem slot the spell was available immediately (after global cooldown), the same spell however had the correct recast cooldown in any other slot. So this leads me to believe that this is indeed a bug in the client.
There is a slim chance its something else, but it doesnt look like it - i could only be certain when i had the executeable from either a later patch or an earlier velious one (we currently use the 22/08/2001 patch exe).
Its actually not even worth investing so much time into this, because its purely cosmetically (you cant cast the first gem anyway when the server prohibits it, but its not greyed out). However, issues like these are like riddles which just scream out loud to be solved by reverse engineering to get a better understanding of the client.
2. Juni 2010
Ever wondered why the endurance bar went up and down very fast in the showcase videos?
Well, it turns out that the clients check for food/drink excluded GMs (thanks IDA Pro). They are never thirsty, however the eqc server did not know that, so GMs were mostly always thirsty/hungry server side and we would sent 0 endurance update to the client. However, the client thought otherwise (he also temporary updates the endurance client side), thats why - when the client updates the endurance bar a small bit of endurance was shown, but every few seconds the server sent 0 endurance back to the client.
I also added a check to remove endurance while being in water during the regular endurance calculation. It actually was already there but not enabled, because when Taz implemented the logic 2008, there were no water check support in the eqc server, i added that in late 2009.