Página 1 de 1

M.3. Classes

Enviado: 17 Ago 2018, 18:44
por Junior_Djjr
Imagem
Imagem
Concluindo esta parte você vai:
Entrar na "deep web" do jogo. Nas profundezas onde você pode conseguir ler e escrever vários valores antes inacessíveis.
Você irá aprender a manipular valores nas classes do jogo, "caminhando" pelas classes etc para encontrar as informações que você deseja em seu mod.

Esta é mais uma parte onde você vai entrar (novamente) em um novo mundo; aprender a, realmente, criar mods como bem entender. Ultrapassar mais limites.
Eu já falei isso anteriormente na parte sobre Condições, e realmente, eu não estava brincando, né?

Se você já tem conhecimento sobre alguma programação orientada à objetos, parabéns! Você já sabe tudo e pode ir pra próxima parte- mentira, o que vamos fazer aqui é muito diferente do que você deve saber. E provavelmente você odiará :)
Se você é novo no assunto, vai achar muito interessante!

Quando eu aprendi (iniciando diretamente em CLEO, sem conhecer OOP) eu tive um pouco de dificuldade no início, e isso é bom, pois agora eu acredito que sei como evitar que você também tenha dificuldade..


Introdução

O GTA III, VC, SA e vários outros jogos foram programados em C++ ou alguma outra programação orientada à objetos (C#, Java etc etc...). É um tipo de programação extremamente útil para jogos, pois nela você pode criar várias "class", onde elas podem organizar uma coleção de informações sobre alguma coisa, como algum veículo, um pedestre, ou até mesmo a câmera do jogo e coisas que você nunca vai saber o que significa.

Imagine: Você tem uma class com nome "Carro", onde, é claro, ela está interligada com algum carro específico dentro do jogo.
Dentro desta class você tem informações como: Qual é a massa; Velocidade máxima; Quantidade de marchas (for english: "Marchas" = "Gears") e Ocupantes:

Código: Selecionar tudo

Carro {
Massa
VelocidadeMáxima
Marchas
Ocupantes
}
Que tipo de data type cada "membro" usaria?

Você consegue imaginar?

Bem, vamos colocar:

Código: Selecionar tudo

Carro {
FLOAT Massa
FLOAT VelocidadeMáxima
BYTE Marchas
BYTE Ocupantes
}
Faz sentido, certo?
1 byte vai até 255 (-128 até 127 caso signed, mas não vem ao caso), só precisamos de 1 byte para a quantidade de marchas e ocupantes, mas a massa e velocidade precisam de números mais definidos: floats.
Atenção: Eu só estou mostrando pseudocodes. Estes códigos não existem, são somente didáticos!
Agora, tente imaginar estes valores preenchidos:

Código: Selecionar tudo

Carro {
FLOAT Massa = 1500.0
FLOAT VelocidadeMáxima = 200.0
BYTE Marchas = 5
BYTE Ocupantes = 3
}
Certo, nós temos um carro com estes valores.

Estas informações são usadas durante o processamento do carro no jogo!
Ou seja, quando o jogo precisar saber quantos ocupantes este carro tem, ele pega o valor em Carro -> Ocupantes.
Quando um novo ocupante entrar no carro, o jogo aumentará este valor (por exemplo, Ocupantes ficará 4)

Mas como exatamente é isso?

Dentro da memória, toda esta "estrutura" (struct) está, é claro, em algum lugar!

É aqui que iremos revisar o que aprendemos sobre Thread Memory.

Vamos supor que o endereço onde está localizado esta estrutura (mais especificamente o início dela), é 1000. (vamos esquecer dos 0xD34DC0DE e simplificar a conta com um 1000)

No início dela, temos:

Código: Selecionar tudo

FLOAT Massa
Que guarda um valor float, onde nosso float tem 4 bytes, lembra?
Portanto, se nós lermos 4 bytes de 1000 + 0 (ou seja, 1000, dã!) nós teremos o valor da massa deste carro (que é 1500.0).

Certo, se nos primeiros 4 bytes nós temos um valor, onde que está o segundo valor? +4!

Se você tem um valor de 4 bytes, basta você subir 4 bytes para "pular" este valor e assim encontrar o próximo. Você já sabe disso.

Enfim, se você ler 1000 + 4 (ou seja, o endereço 1004) você terá outro valor de 4 bytes, agora, a velocidade máxima.

Continuando, em 1000 + 8 você tem a quantidade de marchas! Leia 1 byte para ter o valor de marchas do carro, neste caso em específico, você terá o valor 5.

1000 + 9 tem você a quantidade de ocupantes. Lembre-se, a quantidade de marchas é só 1 byte, portanto, o próximo número foi só +1.

Aumentando mais um byte, portanto, 1000 + 10, nós chegamos no fim. Se você ler 1000 + 10 você encontrará coisas estranhas, pois a nossa class já acabou.
Perceba que esta class tem o total de 10 bytes.


O mundo real

Agora vamos ver um exemplo mais "verdadeiro" do que acontece no modding de GTA (e uns outros jogos):

Código: Selecionar tudo

00000000 RwRGBA          struc ; (sizeof=0x4)
00000000 red             db ?
00000001 green           db ?
00000002 blue            db ?
00000003 alpha           db ?
00000004 RwRGBA          ends
Certo, temos a class RwRGBA (Rw = RenderWare = a engine gráfica do jogo, o nome é basicamente RGBA)
Com certeza você já sabe: RGBA = Red, Green, Blue, Alpha. Simplesmente, uma cor, e com transparência.
O primeiro byte, é o vermelho, depois verde... E assim sucessivamente.
A struct tem 4 bytes no total.

Simplesmente, se o primeiro byte ser o valor hexadecimal FF, o segundo ser 00, terceiro 00 e quarto FF, teríamos a cor vermelha total e opaca. Mesmo de FF0000FF.

Tenha a nota de que essa struct foi retirada do IDA Pro por engenharia reversa, as classes não são originalmente definidas desta maneira (mesmo assim, é semelhante). Mas este formato de leitura nos ajuda muito no nosso trabalho do "modding-hacking".

Imagine que você tenha o ponteiro dela numa variável com nome pRGBA e você quer ter somente o valor azul dela.

Você faria assim:

Código: Selecionar tudo

pRGBA += 2
READ_MEMORY pRGBA 1 FALSE (iBlue)
Ou, mais convenientemente, assim:

Código: Selecionar tudo

pBlue = pRGBA + 2
READ_MEMORY pBlue 1 FALSE (iBlue)
Simples. Você subiu 2 bytes e leu 1 byte deste local, agora, você tem o valor do azul dentro da variável iBlue
Perceba que eu uso p para "pointer" (ponteiro) e i para "integer" (número inteiro) nas variáveis. Está aí uma dica, caso você gostar!

Perceba que você facilmente consegue ler a struct desta class:

Código: Selecionar tudo

00000002 blue            db ?
Inclusive a própria struct diz qual é o offset de cada field.
Em +2 você tem um byte (o b do db é "byte") que aponta para a field blue (o valor do azul).

É muito importante notar que esse 2 não é decimal, e sim hexadecimal!!! Ou seja, é um 0x2.

Portanto, o mais correto seria assim:

Código: Selecionar tudo

pBlue = pRGBA + 0x2
READ_MEMORY pBlue 1 FALSE (iBlue)
Neste caso o resultado é o mesmo, mas escrito de maneira mais correta, você esquecer disso será um desastre dependente do caso.

Vamos lembrar da contagem hexadecimal: 0x10 não é 10 mas sim 16! Não se esqueça da contagem hexadecimal!!! 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B (...)

Outro detalhe importante é que do mesmo modo que 01 (decimal) é igual a 1, você digitar 0x01 (hexadecimal) é igual a 0x1, assim como 0x001, 0x000000001 etc. Só um detalhe para não se confundir. Guarde isto na sua cachola.

Outra coisa que quero te lembrar, é que hexadecimal é simplesmente um modo diferente de digitar números, se você preferir digitar 10 ao invés de 0xA (e vice versa) dá na mesma, não há obrigação.
Portanto, se você está contando de 4 em 4, você pode simplesmente fazer "4, 8, 12, 16", você não é obrigado a digitar "0x4, 0x8, 0xC, 0x10" (que é um tanto estranho para pessoas comuns).

Depois deste tira-dúvidas rápido sobre hexadecimal, vamos voltar ao foco:


Colocando a mão na massa

Vamos aplicar o que aprendemos até agora!

Abaixo temos a CPed (Class Ped) que a comunidade montou (eu o peguei do database do IDA, e limpei ele).

Código: Selecionar tudo

00000000 CPed            struc ; (sizeof=0x79C, mappedto_36)
00000000 physical        CPhysical ?             
00000138 m_pedAudio      CAEPedAudioEntity ?     
00000294 m_pedSpeech     CAEPedSpeechAudioEntity 
00000394 m_weaponAudio   CAEPedWeaponAudioEntity 
0000043C field_43C       db 36 dup(?)
00000460 field_460       db 8 dup(?)             
00000468 field_468       dd ?                    
0000046C m_nPedFlags     dd 4 dup(?)                 
0000047C m_pIntelligence dd ?                         
00000480 m_pPlayerData   dd ?                          
00000484 m_nCreatedBy    db ?                     
00000485 _pad0           db 3 dup(?)
00000488 m_apPedBones    dd 19 dup(?)            
000004D4 m_dwAnimGroup   dd ?                    
000004D8 m_vAnimMovingShiftLocal CVector2D ?     
000004E0 m_acquaintance  CPedAcquaintance ?      
000004F4 m_pWeaponObject dd ?                      
000004F8 m_pGunflashObject dd ?                    
000004FC m_pGogglesObject dd ?                      
00000500 m_pGogglesState dd ?                    
00000504 m_nWeaponGunflashStateLeftHand dw ?     
00000506 field_506       dw ?                    
00000508 m_nWeaponGunflashStateRightHand dw ?    
0000050A field_50A       dw ?                    
0000050C m_pedIK         CPedIK ?                
0000052C field_52C       dd ?                    
00000530 m_nPedState     dd ?                    
00000534 m_dwMoveState   dd ?                    
00000538 field_538       dd ?                    
0000053C field_53C       dd ?
00000540 m_fHealth       dd ?                     
00000544 m_fMaxHealth    dd ?                              
00000548 m_fArmour       dd ?                           
0000054C m_dwTimeTillWeNeedThisPed dd ?          
00000550 m_vAnimMovingShift CVector2D ?                  
00000558 m_fCurrentRotation dd ?                               
0000055C m_fAimingRotation dd ?                  
00000560 m_fHeadingChangeRate dd ?               
00000564 m_dwMoveAnim    dd ?                    
00000568 field_568       dd ?                    
0000056C field_56C       RwV3d ?                 
00000578 field_578       RwV3d ?                 
00000584 m_pContactEntity dd ?                   
00000588 m_pLastVehicle  dd ?                    
0000058C m_pVehicle      dd ?                                  
00000590 field_590       dd ?                    
00000594 field_594       dd ?                    
00000598 m_nPedType      dd ?                                  
0000059C m_pStats        dd ?                    
000005A0 m_aWeapons      CWeapon 13 dup(?)                   
0000070C m_nSavedWeapon  dd ?                    
00000710 m_nDelayedWeapon dd ?                   
00000714 m_dwDelayedWeaponAmmo dd ?
00000718 m_nActiveWeaponSlot db ?                        
00000719 m_nWeaponShootingRate db ?              
0000071A m_nWeaponAccuracy db ?                  
0000071B _pad            db ?
0000071C m_pTargetedObject dd ?                              
00000720 field_720       dd ?
00000724 field_724       dd ?
00000728 field_728       dd ?
0000072C m_nWeaponSkill  db ?                    
0000072D m_nFightingStyle db ?                   
0000072E m_nAllowedAttackMoves db ?              
0000072F field_72F       db ?                    
00000730 m_pFire         dd ?                    
00000734 field_734       dd ?                    
00000738 m_pLookAtEntity dd ?                    
0000073C m_fLookHeading  dd ?                                
00000740 m_dwWeaponModelId dd ?                  
00000744 field_744       dd ?                    
00000748 m_dwLookTime    dd ?                              
0000074C field_74C       dd ?                    
00000750 m_dwTimeWhenDead dd ?                   
00000754 m_nBodypartToRemove db ?                
00000755 field_755       db ?
00000756 m_nMoneyCount   dw ?                    
00000758 field_758       dd ?                    
0000075C field_75C       dd ?
00000760 m_nLastWeaponDamage db ?                
00000761 field_761       db 3 dup(?)
00000764 m_pLastEntityDamaged dd ?               
00000768 field_768       dd ?                    
0000076C m_vTurretOffset CVector ?
00000778 m_fTurretAngleA dd ?
0000077C m_fTurretAngleB dd ?
00000780 m_dwTurretPosnMode dd ?
00000784 m_dwTurretAmmo  dd ?                    
00000788 m_pCoverPoint   dd ?                    
0000078C m_pEnex         dd ?                               
00000790 m_fRemovalDistMultiplier dd ?           
00000794 m_wSpecialModelIndex dw ?               
00000796 field_796       db 2 dup(?)
00000798 field_798       dd ?                    
0000079C CPed            ends
Nota: Você pode ver a classe corretamente definida aqui, mas não inclui os offsets.

Por exemplo, em CPed+0x548 nós temos o valor do colete:

Código: Selecionar tudo

00000548 m_fArmour       dd ?
Tá, mas como nós podemos ter acesso à uma CPed?

Código: Selecionar tudo

GET_PED_POINTER scplayer (pPed)
pPed += 0x548 // m_fArmour
READ_MEMORY pPed 4 FALSE (iArmour)
Ahhhhh... Agora comecei a falar a sua língua, né?

Originalmente na CLEO você tem os seguintes comandos:

Código: Selecionar tudo

GET_PED_POINTER // CPed
GET_VEHICLE_POINTER // CVehicle
GET_OBJECT_POINTER // CObject
Assim você pode pegar a class de algum CHAR (CPed), CAR (CVehicle) ou OBJECT (CObject) para ter acesso à várias (muitas!) informações extras para você usar nos seus mods.

Veja só: Em CPed+0x480 nós temos uma nova class:

Código: Selecionar tudo

00000480 m_pPlayerData   dd ? 
Não está muito claro, mas se você ler este endereço (4 bytes) você vai receber um ponteiro para a CPlayerData.

Código: Selecionar tudo

GET_PED_POINTER scplayer (pPed)
pPed += 0x480 // m_pPlayerData
READ_MEMORY pPed 4 FALSE (pPlayerData)
Pronto, agora nós temos o início da CPlayerData na nossa variável pPlayerData!
E assim nós encontramos mais informações úteis:

Código: Selecionar tudo

00000000 CPlayerData     struc ; (sizeof=0xAC, mappedto_130)
00000000 m_pWanted       dd ?
00000004 m_pClothes      dd ?
00000008 m_ArrestingOfficer dd ?
0000000C m_vecFightMovement CVector2D ?
00000014 m_fMoveBlendRatio dd ?
00000018 m_fTimeCanRun   dd ?
0000001C m_fSprintEnergy dd ?
00000020 m_nChosenWeapon db ?
00000021 m_nCarDangerCounter db ?
00000022 __pad0          db 2 dup(?)
00000024 m_nStandStillTimer dd ?
00000028 m_nHitAnimDelayTimer dd ?
0000002C m_fAttackButtonCounter dd ?
00000030 m_pDangerCar    dd ?
00000034 m_dwPlayerFlags dd ?
00000038 m_PlayerGroup   dd ?
0000003C m_AdrenalineEndTime dd ?
00000040 m_nDrunkenness  db ?
00000041 m_bFadeDrunkenness db ?
00000042 m_nDrugLevel    db ?
00000043 m_nScriptLimitToGangSize db ?
00000044 m_fBreath       dd ?
00000048 m_MeleeWeaponAnimReferenced dd ?
0000004C m_MeleeWeaponAnimReferencedExtra dd ?
00000050 m_fFPSMoveHeading dd ?
00000054 m_fLookPitch    dd ?
00000058 m_fSkateBoardSpeed dd ?
0000005C m_fSkateBoardLean dd ?
00000060 m_pSpecialAtomic dd ?
00000064 m_fGunSpinSpeed dd ?
00000068 m_fGunSpinAngle dd ?
0000006C m_LastTimeFiring dd ?
00000070 m_nTargetBone   dd ?
00000074 m_vecTargetBoneOffset CVector ?
00000080 m_busFaresCollected dd ?
00000084 m_bPlayerSprintDisabled db ?
00000085 m_bDontAllowWeaponChange db ?
00000086 m_bForceInteriorLighting db ?
00000087 _pad1           db ?
00000088 m_DPadDownPressedInMilliseconds dw ?
0000008A m_DPadUpPressedInMilliseconds dw ?
0000008C m_wetness       db ?
0000008D m_playersGangActive db ?
0000008E m_waterCoverPerc db ?
0000008F _pad2           db ?
00000090 m_waterHeight   dd ?
00000094 m_FireHSMissilePressedTime dd ?
00000098 m_LastHSMissileTarget dd ?
0000009C m_nModelIndexOfLastBuildingShot dd ?
000000A0 m_dwPlayerMissile dd ?
000000A4 m_pCurrentProstitutePed dd ?
000000A8 m_pLastProstituteShagged dd ?
000000AC CPlayerData     ends
CPlayerData definido aqui

Se você ler pPlayerData+0x0 (ou seja, simplesmente o mesmo endereço, no mesmo ponteiro) você vai ler isto:

Código: Selecionar tudo

00000000 m_pWanted       dd ?
E assim nós encontramos o CWanted!

Código: Selecionar tudo

00000000 CWanted         struc ; (sizeof=0x29C, mappedto_90)
00000000 m_nChaosLevel   dd ?
00000004 m_nChaosLevelBeforeParole dd ?
00000008 m_nLastTimeWantedDecreased dd ?
0000000C m_nLastTimeWantedLevelChanged dd ?
00000010 m_nTimeOfParole dd ?
00000014 m_fMultiplier   dd ?                    ; float
00000018 m_nCopsInPursuit db ?
00000019 m_nMaxCopsInPursuit db ?
0000001A m_nMaxCopCarsInPursuit db ?
0000001B m_nCopsBeatingSuspect db ?
0000001C m_nChanceOnRoadBlock dw ?
0000001E m_nFlags        db ?
0000001F _pad1F          db ?
00000020 m_nCurrentChaseTime dd ?
00000024 m_nCurrentChaseTimeCounter dd ?
00000028 m_nTimeCounting dd ?
0000002C m_nWantedLevel  dd ?                   
00000030 m_nWantedLevelBeforeParole dd ?
00000034 m_CrimesBeingQd CCrimeBeingQd 16 dup(?)
000001F4 m_pCopsInPursuit dd 10 dup(?)           ; offset
0000021C m_PoliceScannerAudio CAEPoliceScannerAudioEntity ?
00000298 m_bLeavePlayerAlone db ?
00000299 _pad299         db 3 dup(?)
0000029C CWanted         ends
CWanted definido aqui

Você pode usar estes números para fazer checagens, e vários deles você pode editar para fazer alterações no gameplay.

Veja este script que lê o valor do campo m_nCopsInPursuit (que é a quantidade de policiais te perseguindo) e mostra na tela:

Código: Selecionar tudo

SCRIPT_START
{
LVAR_INT scplayer
LVAR_INT pPed pPlayerData pWanted pnCops iCops

GET_PLAYER_CHAR 0 scplayer

main_loop:
WAIT 0

GET_PED_POINTER scplayer (pPed)
pPlayerData = pPed + 0x480 // CPed.CPlayerData
READ_MEMORY pPlayerData 4 FALSE pPlayerData
pWanted = pPlayerData + 0x0 // CPlayerData.pWanted
READ_MEMORY pWanted 4 FALSE pWanted
pnCops = pWanted + 0x18 // CWanted.m_nCopsInPursuit
READ_MEMORY pnCops 1 FALSE (iCops)
PRINT_FORMATTED_NOW "Cops: %i" 1000 (iCops)

GOTO main_loop

}
SCRIPT_END
É claro, eu escrevi o código desta maneira para facilitar o entendimento e ficar mais conveniente.

Você pode otimizar para economizar variáveis e 1 linha:

Código: Selecionar tudo

SCRIPT_START
{
LVAR_INT scplayer
LVAR_INT temp iCops

GET_PLAYER_CHAR 0 scplayer

main_loop:
WAIT 0

GET_PED_POINTER scplayer (temp)
temp += 0x480 // CPed.CPlayerData
READ_MEMORY temp 4 FALSE temp
//temp += 0x0 // CPlayerData.pWanted
READ_MEMORY temp 4 FALSE temp
temp += 0x18 // CWanted.m_nCopsInPursuit
READ_MEMORY temp 1 FALSE (iCops)
PRINT_FORMATTED_NOW "Cops: %i" 1000 (iCops)

GOTO main_loop

}
SCRIPT_END
Assim é um pouco menos organizado (por exemplo, você não guardou uma variável com o CPed, portanto você vai ter que pegar de novo caso precisar) mas mais aconselhável na maioria das vezes.

Os comentários que coloquei no script foram como se fosse uma "conversão" para o formato de linguagens de programação orientadas à objetos. Se você entende delas, conseguiu ter a noção do que nós fizemos aqui.
Chega a ser até engraçado, pois os mods cleos não são feitos em programações orientadas à objetos, mas a gente improvisa!


Se aprofundando

Vamos começar a complicar mais:

Código: Selecionar tudo

00000000 CPed            struc ; (sizeof=0x79C, mappedto_36)
00000000 physical        CPhysical ?             
00000138 m_pedAudio      CAEPedAudioEntity ?     
(...)
Veja que em CPed+0x0 nós temos um CPhysical.

Isto não é um ponteiro para o CPhysical, se você pensou isso, preste mais atenção!

O CPhysical está dentro do CPed, perceba o offset do próximo campo, é 0x138, ou seja, temos 0x138 (312) bytes ali!
Assim como não tem nenhum indicativo de que isso é um ponteiro nem nada, você tem que prestar atenção (eu já passei muitas horas de dor de cabeça por erros bobos assim)

Vamos ir no CPhysical ver o que temos lá:

Código: Selecionar tudo

00000000 CPhysical       struc ; (sizeof=0x138, mappedto_756)
00000000 entity          CEntity ?
00000038 field_34        dd ?
0000003C m_dwLastCollisionTime dd ?
00000040 m_dwFlags       dd ?
00000044 m_vecMoveSpeed  CVector ?
00000050 m_vecTurnSpeed  CVector ?
0000005C m_vecFrictionMoveSpeed CVector ?
00000068 m_vecFrictionTurnSpeed CVector ?
00000074 m_vecForce      CVector ?
00000080 m_vecTorque     CVector ?
0000008C m_fMass         dd ?
00000090 m_fTurnMass     dd ?
00000094 m_fVelocityFrequency dd ?
00000098 m_fAirResistance dd ?
0000009C m_fElasticity   dd ?
000000A0 m_fBuoyancyConstant dd ?
000000A4 m_vecCentreOfMass CVector ?
000000B0 m_pCollisionList dd ?
000000B4 m_pMovingList   dd ?
000000B8 m_bFakePhysics  db ?
000000B9 m_nNumEntitiesCollided db ?
000000BA m_nContactSurface db ?
000000BB field_BB        db ?
000000BC m_apCollidedEntities dd 6 dup(?)
000000D4 m_fMovingSpeed  dd ?
000000D8 m_fDamageIntensity dd ?
000000DC m_pDamageEntity dd ?
000000E0 m_vLastCollisionDirection RwV3d ?
000000EC m_vecLastCollisionPosn CVector ?
000000F8 m_nDamagedPart  dw ?
000000FA field_FA        dw ?
000000FC m_pAttachedTo   dd ?
00000100 m_vAttachOffset RwV3d ?
0000010C m_vAttachRotation RwV3d ?
00000118 m_qAttachRotation CQuaternion ?
00000128 EntityIgnoredCollision dd ?
0000012C m_fContactSurfaceBrightness dd ?
00000130 m_fDynamicLighting dd ?
00000134 m_pShadowData   dd ?
00000138 CPhysical       ends
Oh, percebeu o sizeof=0x138 ali?
Vou parar de dar os links das classes atualizadas e definidas em C++ aqui; todas as classes estão no repositório do DK22Pac! Nosso salvador! Dê uma olhada nos .h — se bem que os .cpp também podem ser interessantes para você. Ver tais arquivos pode te trazer melhor entendimento, principalmente se você é acostumado com OOP.
Perceba que o início do CPhysical, que é o início do CPed, é também o início de um CEntity.

Código: Selecionar tudo

00000000 CEntity         struc ; (sizeof=0x38, mappedto_757)
00000000 placeable       CPlaceable ?
00000018 object          ClumpAtomicUnion ?
0000001C m_nFlags        dd ?
00000020 m_nRandomSeed   dw ?
00000022 m_nModelIndex   dw ?
00000024 m_pReferences   dd ?
00000028 m_pStreamingLink dd ?
0000002C m_nLastScanCode dw ?
0000002E m_iplIndex      db ?
0000002F m_nbInterior    db ?
00000030 m_pLod          dd ?
00000034 m_bNumLodChildren db ?
00000035 m_bNumLodChildrenRendered db ?
00000036 m_nTypeStatus   db ?
00000037 _pad0           db ?
00000038 CEntity         ends
E mais outro! CPlaceable.

Código: Selecionar tudo

00000000 CPlaceable      struc ; (sizeof=0x18)
00000000 __vmt           dd ?                    ; offset
00000004 stransform      CSimpleTransform ?
00000014 m_pMatrix       dd ?                    ; offset
00000018 CPlaceable      ends
Uffa, terminamos.
Você está entendendo onde estamos?
Tudo isso acima está dentro do CPed, logo no início dele (não tecnicamente correto, isto na verdade são os "pais" uns dos outros).
É um pouco mindblow, mas se você ler 4 bytes de CPed+0x4, você estará lendo um campo do CPlaceable, e como visto acima, você estará entrando na CSimpleTransform:

Código: Selecionar tudo

00000000 CSimpleTransform struc ; (sizeof=0x10, mappedto_46)
00000000 m_vPosn         CVector ?
0000000C m_fAngle        dd ?
00000010 CSimpleTransform ends
Certo, e logo no início temos o início de um CVector.

Código: Selecionar tudo

00000000 CVector         struc ; (sizeof=0xC, mappedto_495)
00000000 x               dd ?
00000004 y               dd ?
00000008 z               dd ?
0000000C CVector         ends
Simplesmente um X Y Z...
E como chegar lá?
CPed+0x4
Sua mente já está com bug?
Se você está confuso, reveja lentamente todo o caminho que percorremos.
Entenda, nós só precisamos subir o offset aqui:

Código: Selecionar tudo

00000004 stransform      CSimpleTransform ?
Nada mais, automaticamente chegamos no campo x do CVector.

Curiosamente, aparentemente o CSimpleTransform não é utilizado aqui, o que não é comum de se ver — o mod Active Dashboard aproveita o não uso do CSimpleTransform para guardar informações extras nos veículos, o que não é uma prática muito boa, mas enfim.

Ou seja, não adianta tentar ler, vai retornar 0.0, não sei o motivo, mas pelo menos aprendemos muito aqui.

Nós podemos testar isso lendo outra coisa lá atrás no CPhysical:

Código: Selecionar tudo

0000008C m_fMass         dd ?
Para chegarmos aí é só CPed+0x8C, simplesmente.

E assim nós podemos saber o peso do CJ:

Código: Selecionar tudo

GET_PED_POINTER scplayer (pPed)
pMass = pPed + 0x8C // CPed.CPhysical.m_fMass
READ_MEMORY pMass 4 FALSE (fMass)
Ele tem 70 kgs :peepo1:

Experimente escrever um valor alto, como 1000.0 e encostar num carro!
Ou abaixar um pouco. Fará o CJ pular mais alto e corrigirá a coisa irreal de empurrar carros com o corpo.

Num último exemplo, vamos no CVehicle:

Código: Selecionar tudo

00000000 CVehicle        struc ; (sizeof=0x5A0, mappedto_755)
00000000 physical        CPhysical ?
00000138 m_vehicleAudio  CAEVehicleAudioEntity ?
00000384 m_pHandlingData dd ?
00000388 m_pFlyingHandlingData dd ?
0000038C m_nHandlingFlags dd ?
00000390 m_autoPilot     CAutoPilot ?
00000428 m_nFlags        db 8 dup(?)
00000430 m_nCreationTime dd ?
00000434 m_nPrimaryColor db ?
00000435 m_nSecondaryColor db ?
00000436 m_nTertiaryColor db ?
00000437 m_nQuaternaryColor db ?
00000438 m_anExtras      db 2 dup(?)
0000043A m_anUpgrades    dw 15 dup(?)
00000458 m_fWheelScale   dd ?
0000045C m_nAlarmState   dw ?
0000045E m_nForcedRandomRouteSeed dw ?
00000460 m_pDriver       dd ?
00000464 m_apPassengers  dd 8 dup(?)
00000484 m_nNumPassengers db ?
00000485 m_nNumGettingIn db ?
00000486 m_nGettingInFlags db ?
00000487 m_nGettingOutFlags db ?
00000488 m_nMaxPassengers db ?
00000489 m_nWindowsOpenFlags db ?
0000048A m_nNitroBoosts  db ?
0000048B m_nSpecialColModel db ?
0000048C m_pEntityWeAreOn dd ?
00000490 m_pFire         dd ?
00000494 m_fSteerAngle   dd ?
00000498 m_f2ndSteerAngle dd ?
0000049C m_fGasPedal     dd ?
000004A0 m_fBreakPedal   dd ?
000004A4 m_nCreatedBy    db ?
000004A5 _pad0           db ?
000004A6 m_wExtendedRemovalRange dw ?
000004A8 m_nBombLightsWinchFlags db ?
000004A9 m_nGunsFlags    db ?
000004AA m_nUsedForCover db ?
000004AB m_nAmmoInClip   db ?
000004AC m_nPacMansCollected db ?
000004AD m_nPedsPositionForRoadBlock db ?
000004AE m_nNumCopsForRoadBlock db ?
000004AF _pad1           db ?
000004B0 m_fDirtLevel    dd ?
000004B4 m_nCurrentGear  db ?
000004B5 _pad2           db 3 dup(?)
000004B8 m_fGearChangeCount dd ?
000004BC m_fWheelSpinForAudio dd ?
000004C0 m_fHealth       dd ?
000004C4 m_pTractor      dd ?
000004C8 m_pTrailer      dd ?
000004CC m_pWhoInstalledBombOnMe dd ?
000004D0 m_dwTimeTillWeNeedThisCar dd ?
000004D4 m_dwGunFiringTime dd ?
000004D8 m_dwTimeWhenBlowedUp dd ?
000004DC m_wCopsInCarTimer dw ?
000004DE m_wBombTimer    dw ?
000004E0 m_pWhoDetonatedMe dd ?
000004E4 m_fVehicleFrontGroundZ dd ?
000004E8 m_fVehicleRearGroundZ dd ?
000004EC _i_nu_field_4EC db ?
000004ED _nu_field_4ED   db 11 dup(?)
000004F8 m_dwDoorLock    dd ?
000004FC m_dwProjectileWeaponFiringTime dd ?
00000500 m_dwAdditionalProjectileWeaponFiringTime
00000504 m_dwTimeForMinigunFiring dd ?
00000508 m_nLastWeaponDamageType db ?
00000509 _pad3           db 3 dup(?)
0000050C m_pLastDamageEntity dd ?
00000510 _nu_field_510   db ?
00000511 _i_nu_field_511 db ?
00000512 _i_nu_field_512 db ?
00000513 m_nVehicleWeaponInUse db ?
00000514 m_nHornCounter  dd ?
00000518 randomIdRelatedToSiren db ?
00000519 m_nCarHornTimer db ?
0000051A field_51A       db ?
0000051B m_nHasslePosId  db ?
0000051C m_FrontCollPoly CStoredCollPoly ?
00000548 m_RearCollPoly  CStoredCollPoly ?
00000574 m_anCollisionLighting db 4 dup(?)
00000578 m_pOverheatParticle dd ?
0000057C m_pFireParticle dd ?
00000580 m_pDustParticle dd ?
00000584 m_dwRenderLights dd ?
00000588 m_pCustomCarPlate dd ?
0000058C m_fSteeringLeftRight dd ?
00000590 m_dwVehicleClass dd ?
00000594 m_dwVehicleSubClass dd ?
00000598 m_wPreviousPaintjobTxd dw ?
0000059A m_wPaintJobTxd  dw ?
0000059C m_pPaintJobTexture dd ?
000005A0 CVehicle        ends
E ainda, CVehicle vem da CAutomobile (de fato, ao usar o comando GET_VEHICLE_POINTER você está pegando um CAutomobile que contém o CVehicle no início):

Código: Selecionar tudo

00000000 CAutomobile     struc ; (sizeof=0x988, mappedto_763)
00000000 vehicle         CVehicle ?
000005A0 m_damageManager CDamageManager ?
000005B8 m_doors         CDoor 6 dup(?)
00000648 m_aCarNodes     dd 25 dup(?)
000006AC m_panels        CBouncingPanel 3 dup(?)
0000070C m_swingingChassis CDoor ?
00000724 m_wheelColPoint CColPoint 4 dup(?)
000007D4 wheelsDistancesToGround1 dd 4 dup(?)
000007E4 wheelsDistancesToGround2 dd 4 dup(?)
000007F4 field_7F4       dd 4 dup(?)
00000804 field_800       dd ?
00000808 field_804       dd ?
0000080C field_80C       dd ?
00000810 field_810       dd 4 dup(?)
00000820 field_81C       db 4 dup(?)
00000824 field_820       dd ?
00000828 m_fWheelRotation dd 4 dup(?)
00000838 field_838       dd 4 dup(?)
00000848 m_fWheelSpeed   dd 4 dup(?)
00000858 field_858       dd 4 dup(?)
00000868 taxiAvaliable   db ?
00000869 field_869       db ?
0000086A field_86A       db ?
0000086B field_867       db ?
0000086C m_wMiscComponentAngle dw ?
0000086E field_86E       dw ?
00000870 m_dwBusDoorTimerEnd dd ?
00000874 m_dwBusDoorTimerStart dd ?
00000878 field_878       dd ?
0000087C wheelOffsetZ    dd 4 dup(?)
0000088C field_88C       dd 3 dup(?)
00000898 m_fFrontHeightAboveRoad dd ?
0000089C m_fRearHeightAboveRoad dd ?
000008A0 m_fCarTraction  dd ?
000008A4 m_fNitroValue   dd ?
000008A8 field_8A4       dd ?
000008AC m_fRotationBalance dd ?
000008B0 m_fMoveDirection dd ?
000008B4 field_8B4       dd 6 dup(?)
000008CC field_8C8       dd 6 dup(?)
000008E4 m_dwBurnTimer   dd ?
000008E8 m_pWheelCollisionEntity dd 4 dup(?)
000008F8 m_vWheelCollisionPos CVector 4 dup(?)
00000928 field_924       db ?
00000929 field_925       db ?
0000092A field_926       db ?
0000092B field_927       db ?
0000092C field_928       db ?
0000092D field_929       db ?
0000092E field_92A       db ?
0000092F field_92B       db ?
00000930 field_92C       db ?
00000931 field_92D       db ?
00000932 field_92E       db ?
00000933 field_92F       db ?
00000934 field_930       db ?
00000935 field_931       db ?
00000936 field_932       db ?
00000937 field_933       db ?
00000938 field_934       db ?
00000939 field_935       db ?
0000093A field_936       db ?
0000093B field_937       db ?
0000093C field_938       db ?
0000093D field_939       db ?
0000093E field_93A       db ?
0000093F field_93B       db ?
00000940 field_93C       db ?
00000941 field_93D       db ?
00000942 field_93E       db ?
00000943 field_93F       db ?
00000944 field_940       dd ?
00000948 field_944       dd ?
0000094C m_fDoomVerticalRotation dd ?
00000950 m_fDoomHorizontalRotation dd ?
00000954 m_fForcedOrientation dd ?
00000958 m_fUpDownLightAngle dd 2 dup(?)
00000960 m_nNumContactWheels db ?
00000961 m_nWheelsOnGround db ?
00000962 field_962       db ?
00000963 field_963       db ?
00000964 field_964       dd ?
00000968 field_968       dd 4 dup(?)
00000978 pNitroParticle  dd 2 dup(?)
00000980 field_980       db ?
00000981 field_981       db ?
00000982 field_982       dw ?
00000984 field_984       dd ?
00000988 CAutomobile     ends
A CAutomobile tem um total de 2,44 KB.
GIGANTESCA.
Quando nós fazemos isso:

Código: Selecionar tudo

GET_VEHICLE_POINTER hCar (pVehicle)
Nós estamos adquirindo a CAutomobile, que contém a CVehicle, que contém a CEntity, que contém a CPhysical... E todas as outras classes espalhadas entre elas, como CDoor, CFire etc etc etc... Basta você encontrar o caminho que você conseguirá milhares de dados úteis.

No CVehicle nós podemos por exemplo ter o ponteiro do handling do veículo:

Código: Selecionar tudo

00000384 m_pHandlingData dd ?
Veja que quando o valor é um ponteiro para outra class, o nome da field tem um "p" (ponteiro) no início, e, sempre o campo tem 4 bytes (os ponteiros sempre têm 4 bytes num aplicativo 32 bits!)

Basta nós lermos lá para ter as informações do handling, ou, mais especificamente, um tHandlingData:

Código: Selecionar tudo

00000000 tHandlingData   struc ; (sizeof=0xE0, mappedto_123)
00000000 index           dd ?
00000004 fMass           dd ?
00000008 field_8         dd ?
0000000C fTurnMass       dd ?
00000010 fDragMult       dd ?
00000014 centreOfMass    RwV3d ?
00000020 nPercentSubmerged db ?
00000021 field_21        db ?
00000022 field_22        db ?
00000023 field_23        db ?
00000024 fBuoyancyConstant dd ?
00000028 fTractionMultiplier dd ?
0000002C transmissionData cTransmission ?
00000094 fBrakeDeceleration dd ?
00000098 fBrakeBias      dd ?
0000009C bABS            db ?
0000009D field_9D        db ?
0000009E field_9E        db ?
0000009F field_9F        db ?
000000A0 fSteeringLock   dd ?
000000A4 fTractionLoss   dd ?
000000A8 fTractionBias   dd ?
000000AC fSuspensionForceLevel dd ?
000000B0 fSuspensionDampingLevel dd ?
000000B4 fSuspensionHighSpdComDamp dd ?
000000B8 fSuspensionUpperLimit dd ?
000000BC fSuspensionLowerLimit dd ?
000000C0 fSuspensionBiasBetweenFrontAndRear dd ?
000000C4 fSuspensionAntiDiveMultiplier dd ?
000000C8 fCollisionDamageMultiplier dd ?
000000CC modelFlags      dd ?
000000D0 handlingFlags   dd ?
000000D4 fSeatOffsetDistance dd ?
000000D8 nMonetaryValue  dd ?
000000DC frontLights     db ?
000000DD rearLights      db ?
000000DE animGroup       db ?
000000DF field_DF        db ?
000000E0 tHandlingData   ends
Ou seja, por exemplo, os freios:

Código: Selecionar tudo

00000094 fBrakeDeceleration dd ?
Para nós alterarmos os freios do nosso carro, basta:

Código: Selecionar tudo

SCRIPT_START
{
LVAR_INT scplayer
LVAR_INT hCar pVehicle pHandling pBrakeDeceleration

GET_PLAYER_CHAR 0 scplayer

main_loop:
WAIT 0

IF TEST_CHEAT BRAKE
    IF IS_CHAR_SITTING_IN_ANY_CAR scplayer
        STORE_CAR_CHAR_IS_IN_NO_SAVE scplayer hCar
        GET_VEHICLE_POINTER hCar (pVehicle)
        pHandling = pVehicle + 0x384 // CAutomobile.CVehicle.m_pHandlingData
        READ_MEMORY pHandling 4 FALSE (pHandling) // tHandlingData
        pBrakeDeceleration = pHandling + 0x94 // tHandlingData.fBrakeDeceleration
        WRITE_MEMORY pBrakeDeceleration 4 0.0 FALSE
    ENDIF
ENDIF

GOTO main_loop

}
SCRIPT_END
No exemplo acima eu desativei totalmente os freios do veículo atual do player.
Detalhe importante sobre este exemplo: O handling dos veículos são compartilhados por modelo, portanto, se você ativou em um Elegy, todos os carros de modelo Elegy irão sofrer as alterações. Para corrigir isso é necessário usar IndieVehHandlings.cs (um cleo que vem em vários mods meus, como Tuning Mod e Real Traffic Fix). Neste caso, você pode simplesmente colocar um WAIT (para dar tempo do IndieVehHandlings fazer o trabalho), já deve servir, mas o mais aconselhável é usar uma função para checar se o ponteiro do handling recebeu o patch. Basta abrir o .cs com alguma versão mais atual do Sanny Builder que você terá muitas informações e códigos prontos, no entanto, até agora só no formato Sanny Builder, de fato eu penso em recriá-lo em .asi.
Eu ainda lhe enviarei a lista dessas classes com offsets para você usar.
 
 
Revisão e mais detalhes:

Código: Selecionar tudo

00000050 m_wTimesUsed    dw ?
50 — offset em hexadecimal.
m_wTimesUsed — nome da field, geralmente com letras dando dicas do seu conteúdo. Por exemplo se tem um "f" no início nós sabemos que é um float etc.
dw — a segunda letra indica a quantidade de bytes (BYTE, WORD, DWORD), como já foi explicado nas partes anteriores.

Código: Selecionar tudo

00000034 m_pHitColModel  dd ?
O p no início do nome da field com tamanho de 4 bytes indicam que isso é um ponteiro para outra class (ou seja, você tem que ler este valor, e o resultado será o endereço da outra class).

Código: Selecionar tudo

000000AC field_AC        dd ?
O nome da field estando field_{offset} é porque simplesmente está sem nome (a comunidade não colocou ou simplesmente já colocaram mas a struct que você está olhando está desatualizada).
Lembre-se, 99,99% das fields são usadas no jogo por algum motivo. Esse monte de field pode ter coisas importantes, ou não, e, como eu disse, você pode ter as classes com nomes atualizados aqui, na qual pode incluir campos ainda não nomeados aqui.

Código: Selecionar tudo

00000074 m_vecForce      CVector ?
00000080 m_vecTorque     CVector ?
Se notavelmente não é um ponteiro, e normalmente há o nome de uma classe do lado (geralmente, mas não sempre, iniciadas com C), e tendo o próximo campo numa distância do tamanho do CVector (que é 0xC, ou seja, 12 bytes), é porque não é um ponteiro, e sim a classe inteira está ali ali.

Código: Selecionar tudo

000002B0 m_anPrimaryColors db 8 dup(?)
dup — indica um array, ou seja, não é só 1 elemento de 1 byte, mas sim, neste caso, 8 elementos de 1 byte. Neste exemplo específico (do CVehicle) é o offset para todas as 8 possíveis variações de cores primárias do veículo (perceba, os veículos suportam só 8 variações de cores!)

Código: Selecionar tudo

00000000 materials       dd ?                    ; RpMaterial **
Dois asteriscos juntos ("**") indicam um ponteiro para um ponteiro. Isso quer dizer que...

Código: Selecionar tudo

READ_MEMORY pointer 4 FALSE (pointer)
READ_MEMORY pointer 4 FALSE (value)
Entendeu?
  
"Como eu obtenho acesso à class X?"
Isso varia demais, muito mesmo!
Geralmente, por base de uma class você encontra várias outras. Você tem que encontrar o caminho, como já explicado.
Muitas vezes elas estão em um endereço estático do .exe, como por exemplo a CCamera que no Crack 1.0 US sempre fica (literalmente) em 0xB6F028.

Certo, acredito que já está bem explicado.

Download das structs:

Para você que não quer usar o IDA Pro, você pode baixar o IDA.txt que é um arquivo com a lista de todas as structs documentadas pela comunidade. Eu uso muito isto!
Vou tentar deixá-lo atualizado como possível.
Há também o IDA - VC.txt que são as structs do GTA Vice City


Eu quero deixar claro que, se você acha isso poderoso, você tem razão. Na verdade, você ainda nem deve ter noção do real poder de saber fazer este tipo de coisa.
Com um simples GET_VEHICLE_POINTER é possível você até trocar texturas de um material específico do modelo do carro.
Praticamente (se não todos) os meus mods mais complexos/avançados usam isso... É ir além do normalmente acessível.

Você ter aprendido isso multiplicou (e muito) suas possibilidades de mods. Nós já estamos chegando ao fim das partes mais avançadas deste tutorial, você estando aqui já deve saber muita coisa, ou pelo menos já tem as portas abertas para começar a saber.

Próxima parte:
M.4. Chamando funções (CALL)
 

Re: M.3. Classes

Enviado: 17 Ago 2018, 18:45
por Junior_Djjr
Eu gostaria de deixar MUITO claro que os tutoriais sempre são revisados, e este sofreu MUITA alteração (inclusive eu tinha dito várias coisas erradas antes), ainda que de lá pra cá as documentações do GTA SA cresceram MUITO:
Imagem
Imagem
O download do IDA.txt também foi atualizado.

Re: M.3. Classes

Enviado: 04 Jan 2019, 20:17
por Legacy
Como é que a comunidade de modding do GTA SA consegue descobrir o que cada classe, endereço e variável representa?
Será que dá para descobrir para outros jogos, tipo CS:GO e fazer alguma integração com um teclado RGB, um celular ou algum servidor HTTP para mostrar vida, colete, munição, etc? Vou tentar abrir só para ver o que dá.

Deve ser assim que nos campeonatos eles mudam as cores dos holofotes para a cor do time que ganhou, os indicadores no placar, etc.

Re: M.3. Classes

Enviado: 04 Jan 2019, 21:05
por Junior_Djjr
Legacy escreveu:
04 Jan 2019, 20:17
Como é que a comunidade de modding do GTA SA consegue descobrir o que cada classe, endereço e variável representa?
Será que dá para descobrir para outros jogos, tipo CS:GO e fazer alguma integração com um teclado RGB, um celular ou algum servidor HTTP para mostrar vida, colete, munição, etc? Vou tentar abrir só para ver o que dá.
É realmente um trabalho monstruoso, os modders de GTA SA são guerreiros.
Mas a integração com teclado RGB no CS:GO já existe, eu sem querer me topei com isto no Github quando eu estava procurando exemplos de implementação pro meu mouse. Acho que é só pra Logitech.
Era um projeto que tinha implementação para vários jogos ao mesmo tempo.

Re: M.3. Classes

Enviado: 28 Ago 2020, 11:43
por kurt
Próxima parte:
(em breve) #  TWO YEAR LATER
 
Editado pela última vez por Junior_Djjr em 17 Ago 2018, 18:44, em um total de 1 vez.