Project 1999

Go Back   Project 1999 > Blue Community > Blue Server Chat

Closed Thread
 
Thread Tools Display Modes
  #1  
Old 09-30-2019, 01:08 PM
Castamere Castamere is offline
Fire Giant


Join Date: Jul 2014
Posts: 522
Default

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
Frankly this argument annoys me. You guys underestimate the difficulty of client side changes. We don't have access to Client source code. We have very limited dissassembly skillsets, and occasionally we rely on pseudocode. Haynar is better than I am at finding specific memory addresses and offsets, and I'm somewhat decent at finding/following code paths for functions to hook and modify their arguments and/or return values. Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.

The Client psuedocode is 468,710 lines of code long, and most of it looks a lot like this:

Code:
//----- (0041ACE9) --------------------------------------------------------
signed int __thiscall sub_41ACE9(_DWORD *this, unsigned int a2)
{
  _DWORD *v2; // esi
  int v3; // edx
  int v4; // eax
  int v5; // edi
  signed int v6; // ebx
  int v7; // edi
  int v8; // eax
  int v9; // edi
  int v10; // eax
  int v11; // eax
  int v12; // eax
  int v13; // eax
  int v14; // edi
  char v15; // al
  int v16; // eax
  signed int v17; // ecx
  int v18; // eax
  int v19; // ebx
  signed int v20; // edi
  _DWORD *v21; // eax
  _DWORD *v22; // eax
  int v23; // eax
  int v24; // eax
  int v25; // edi
  int v26; // eax
  signed int v28; // [esp+Ch] [ebp-4h]
  _DWORD *v29; // [esp+Ch] [ebp-4h]

  v2 = this;
  v28 = sub_40E722((_DWORD *)((char *)this + *(_DWORD *)(this[1] + 4) + 4), a2);
  v4 = v2[2];
  if ( v4
    && !*(_BYTE *)(v4 + 580)
    && !*(_BYTE *)(v4 + 598)
    && !sub_4167E2((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4)) )
  {
    v29 = (_DWORD *)(*(int (**)(void))(*(_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4) + 64))();
    v5 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
    v6 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
    if ( v6 < (unsigned __int8)sub_5ED510(v29) )
    {
      v7 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
      if ( (unsigned __int8)sub_5ED510(v29) >= v7 + 2 )
        v5 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516) + 2;
      else
        v5 = (unsigned __int8)sub_5ED510(v29);
    }
    v8 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
    v9 = sub_44A448(v5, *(unsigned __int8 *)(v8 + 4508), a2, (int)v29);
    if ( sub_40E722((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), a2) < v9 )
      v9 = sub_40E722((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), a2);
    v10 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
    v11 = sub_4184F4(v2, a2, *(_DWORD *)(v10 + 4504));
    v28 = v9;
    if ( v9 <= v11 )
      v28 = v11;
  }
  v12 = v2[2];
  if ( v12 )
  {
    if ( !*(_BYTE *)(v12 + 580) )
    {
      v13 = sub_40E934((int)v2, v3, 122, 0);
      v14 = v13;
      if ( v13 )
      {
        sub_44D0D0(*(_DWORD *)(v13 + 4));
        if ( v15 )
        {
          sub_40CBD6(*(_DWORD *)(v14 + 4));
          if ( v16 )
          {
            if ( *(_DWORD *)(v16 + 48) == a2 )
            {
              v17 = *(_DWORD *)(v16 + 240);
              if ( v17 > 0 && v17 < 101 )
                v28 = v28 * (100 - v17) / 100;
            }
          }
        }
      }
    }
  }
  v18 = v2[2];
  v19 = 0;
  if ( v18 && !*(_BYTE *)(v18 + 580) )
  {
    v20 = 0;
    do
    {
      if ( sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20) )
      {
        v21 = (_DWORD *)sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20);
        if ( !sub_5ECCC0(v21) )
        {
          v22 = (_DWORD *)sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20);
          v23 = sub_5E3210(v22, a2, v28, 1);
          if ( v23 )
          {
            if ( v23 > v19 )
              v19 = v23;
          }
        }
      }
      ++v20;
    }
    while ( v20 < 22 );
    if ( v19 )
      v28 += v19;
    if ( a2 == 35 )
    {
      if ( *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 136) )
      {
        v24 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
        v25 = sub_5E3210(*(_DWORD **)(v24 + 136), 35, v28, 1);
        v26 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
        if ( sub_5ECC00(*(_DWORD **)(v26 + 136)) == 12 )
        {
          if ( v25 )
            v28 += v25;
        }
      }
    }
  }
  if ( v28 > 252 && sub_44A273(a2) )
    v28 = 252;
  return v28;
}
// 40CBD6: using guessed type double __stdcall sub_40CBD6(_DWORD);
// 44D0D0: using guessed type double __cdecl sub_44D0D0(_DWORD);
Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. In this function, it's handling a lot of processing on those values to check various caps based on class and skill ID, which it really should have no reason to do because we just want it to display what the server tells us it is.

So, we hook it. Hooking is essentially rewriting the running code in memory at the location of this function to do a JMP (Jump/Detour) to our own custom function. At which point we access the Skill Value directly, using a global client pointer to the character's data, and return it:

Code:
signed int	CHooks::SkillCapCheck2_Detour(unsigned int a1) {
	return ((CharData2 *)((*(CharData **)0x905D00)->ExtendedData->pCharData2))->Skill[a1];
}
And this is actually one of the easier examples.
It wasn't intended to be a jab at you or your staff. I realize how it may have come across that way. I'll retract that statement, based on all the smart stuff you just posted.
  #2  
Old 09-30-2019, 01:20 PM
kaev kaev is offline
Planar Protector


Join Date: Sep 2011
Posts: 1,909
Default

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
...
Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. ...
Numeric skill display in the client was added some time after release, might have been post-Kunark release, all you got were the "Awful/Below Average/.../Master" strings at first. I hand-parsed logs to work out what my characters' skills were at and what the level caps were from the numeric skill-up messages. My inner Nilbog wants to see this true on green.
  #3  
Old 09-30-2019, 05:18 PM
Secrets Secrets is offline
VIP / Contributor

Secrets's Avatar

Join Date: Oct 2009
Posts: 1,354
Default

Quote:
Originally Posted by kaev [You must be logged in to view images. Log in or Register.]
Numeric skill display in the client was added some time after release, might have been post-Kunark release, all you got were the "Awful/Below Average/.../Master" strings at first. I hand-parsed logs to work out what my characters' skills were at and what the level caps were from the numeric skill-up messages. My inner Nilbog wants to see this true on green.
The strings were generated from actual numerical values. Evidence of this exists as early as the client shipped in 1999 on the disks.
__________________
Engineer of Things and Stuff, Wearer of Many Hats

“Knowing yourself is the beginning of all wisdom.” — Aristotle
  #4  
Old 09-30-2019, 01:26 PM
Mblake81 Mblake81 is offline
Banned


Join Date: Jan 2011
Location: Bristlebane <Reckless Fury>
Posts: 1,811
Default It's a Unix System

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
Frankly this argument annoys me. You guys underestimate the difficulty of client side changes. We don't have access to Client source code. We have very limited dissassembly skillsets, and occasionally we rely on pseudocode. Haynar is better than I am at finding specific memory addresses and offsets, and I'm somewhat decent at finding/following code paths for functions to hook and modify their arguments and/or return values. Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.

The Client psuedocode is 468,710 lines of code long, and most of it looks a lot like this:

Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. In this function, it's handling a lot of processing on those values to check various caps based on class and skill ID, which it really should have no reason to do because we just want it to display what the server tells us it is.

So, we hook it. Hooking is essentially rewriting the running code in memory at the location of this function to do a JMP (Jump/Detour) to our own custom function. At which point we access the Skill Value directly, using a global client pointer to the character's data, and return it:

And this is actually one of the easier examples.
-Programmed from Rogeans SGI Crimson & Machintosh Quadra

Now we wait for the storm to steal the dino dna. [You must be logged in to view images. Log in or Register.]
Last edited by Mblake81; 09-30-2019 at 01:29 PM..
  #5  
Old 09-30-2019, 01:32 PM
Bardp1999 Bardp1999 is offline
Planar Protector

Bardp1999's Avatar

Join Date: Feb 2015
Location: Maceland
Posts: 1,443
Default

Quote:
Originally Posted by Mblake81 [You must be logged in to view images. Log in or Register.]
Now we wait for the storm to steal the dino dna. [You must be logged in to view images. Log in or Register.]
[You must be logged in to view images. Log in or Register.]
__________________
Forum Quest
Spyder73 (BANNED)
NecroP1999 (BANNED)

#LobsterClan
#FreeWuTang
  #6  
Old 09-30-2019, 05:13 PM
Secrets Secrets is offline
VIP / Contributor

Secrets's Avatar

Join Date: Oct 2009
Posts: 1,354
Default

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.
On that note...

The code for cycling through targets did not exist in any client prior to 2004. Please stop using "I read it in a Usenet group" or "it was bound to tab". It's fake news. The only thing bound to tab was cycle between self and target.
__________________
Engineer of Things and Stuff, Wearer of Many Hats

“Knowing yourself is the beginning of all wisdom.” — Aristotle
  #7  
Old 09-30-2019, 05:19 PM
Danth Danth is offline
Planar Protector


Join Date: Oct 2009
Posts: 3,326
Default

Quote:
Originally Posted by Secrets [You must be logged in to view images. Log in or Register.]
On that note...

The code for cycling through targets did not exist in any client prior to 2004. Please stop using "I read it in a Usenet group" or "it was bound to tab". It's fake news. The only thing bound to tab was cycle between self and target.
I posted elsewhere but it got lost in the shuffle, but when did names start to "blink" once targeted? I noticed the other day they didn't do that in the old Tutorial, and most probably did not do that in the EQ beta either since the Tutorial.exe was based on that very old code. I have no personal recollection as to when that particular feature was added, but thinking about it....I remember it being really hard to tell what I had targeted if I pulled several things that had the same name. No recollection at all when it changed.

Names DO blink on the standard version of the Trilogy client so it was added early (again the tutorial is a separate .exe) I just don't remember whether it was a beta or an early-launch addition. I am NOT suggesting this for P1999--merely asking for the sake of trivia.

Danth
Last edited by Danth; 09-30-2019 at 05:22 PM..
  #8  
Old 09-30-2019, 05:28 PM
Baler Baler is offline
Planar Protector

Baler's Avatar

Join Date: Mar 2014
Posts: 9,523
Default

Quote:
Originally Posted by Secrets [You must be logged in to view images. Log in or Register.]
On that note...

The code for cycling through targets did not exist in any client prior to 2004. Please stop using "I read it in a Usenet group" or "it was bound to tab". It's fake news. The only thing bound to tab was cycle between self and target.
#classless
__________________
  #9  
Old 09-30-2019, 09:12 PM
DMN DMN is offline
Planar Protector

DMN's Avatar

Join Date: May 2016
Location: My own special hell
Posts: 3,364
Default

Quote:
Originally Posted by Secrets [You must be logged in to view images. Log in or Register.]
On that note...

The code for cycling through targets did not exist in any client prior to 2004. Please stop using "I read it in a Usenet group" or "it was bound to tab". It's fake news. The only thing bound to tab was cycle between self and target.
Really? I thought it was "target and last target". Defaulting to self only when there is no last target targettable. But that was a long ass time ago.
  #10  
Old 09-30-2019, 11:46 AM
Castamere Castamere is offline
Fire Giant


Join Date: Jul 2014
Posts: 522
Default

I'm not sure the integrity of the server is at stake.
Closed Thread


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 07:14 AM.


Everquest is a registered trademark of Daybreak Game Company LLC.
Project 1999 is not associated or affiliated in any way with Daybreak Game Company LLC.
Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.