Jump to content

5496 issue implementation help


Recommended Posts

A year ago i posted a request for setPedAnimationProgress scripting function

And there was no progress, it still has "new" status.

I tried to implement it myself, but nothing work :(

And i am asking for help now.

This is original GTA opcode handler for 0x0614(0614: set_actor $PLAYER_ACTOR animation "GYM_BP_DOWN" progress_to $1822 // 0.0 to 1.0) opcode.

With my(and not only my comments).

  
.text:00491802     ; __linkproc__ opcode_0614 
.text:00491802     @@opcode_0614:                          ; CODE XREF: _opcode_handler_15+37j 
.text:00491802                                             ; DATA XREF: .text:__linkproc__ opcode_tableo 
.text:00491802 234                 push    1               ; set_actor %1d% animation %2h% progress_to %3d% // 0.0 to 1.0 
.text:00491804 238                 mov     ecx, esi 
.text:00491806 238                 call    CScriptThread__getNumberParams 
.text:0049180B 234                 mov     ecx, _opcodeParameters 
.text:00491811 234                 push    ecx             ; int 
.text:00491812 238                 mov     ecx, _PedPool 
.text:00491818 238                 call    ?atHandle@?$CPool@VCPed@@@@QAEPAVCVehicle@@I@Z ; CPed * CPool<CPed>::atHandle (u32 h); 
.text:0049181D 234                 push    18h 
.text:0049181F 238                 lea     edx, [esp+238h+var_1E4] 
.text:00491823 238                 push    edx 
.text:00491824 23C                 mov     ecx, esi 
.text:00491826 23C                 mov     edi, eax   
.text:00491828 23C                 call    _CScriptThread__getStringParam  
.text:0049182D 234                 mov     ecx, [edi+18h] 
.text:00491830 234                 lea     eax, [esp+234h+var_1E4] 
.text:00491834 234                 push    eax 
.text:00491835 238                 push    ecx 
  
; This function is actually FUNC_RpAnimBlendClumpGetAssociation_str, stores pointer to CAnimBlendAssociationSAInterface in EAX 
.text:00491836 23C                 call    sub_4D6870    
  
  
.text:0049183B 23C                 add     esp, 8 
.text:0049183E 234                 push    1               ; count 
.text:00491840 238                 mov     ecx, esi 
  
;moving our pointer to EDI 
.text:00491842 238                 mov     edi, eax  
  
  
.text:00491844 238                 call    CScriptThread__getNumberParams 
  
; if pointer is zero jump to return else continue running 
.text:00491849 234                 test    edi, edi  
.text:0049184B 234                 jz      loc_492203  
  
;Moving CAnimBlendHierarchySAInterface pointer from CAnimBlendAssociationSAInterface in EDX 
.text:00491851 234                 mov     edx, [edi+14h]  
  
;It seems like loading fTotalTime field into FPU 
.text:00491854 234                 fld     dword ptr [edx+10h] 
  
;I cant understand what this code do, but it is floating point  multiplication i think (using the stack? o_O) 
.text:00491857 234                 push    ecx 
.text:00491858 238                 fmul    _opcodeParameters 
  
;store in ecx pointer to CAnimBlendAssociationSAInterface 
.text:0049185E 238                 mov     ecx, edi  
  
.text:00491860 238                 fstp    [esp+238h+var_238] 
  
;calling function that actually sets animation frame position, takes one float argument, also uses data from ECX(there stored our pointer to that time) 
.text:00491863 238                 call    sub_4CEA80      ; set animation progress 
  
.text:00491868 234                 xor     al, al 
.text:0049186A 234                 jmp     loc_492AAB 
  

the function beginng

  
  
.text:004CEA80     arg_0           = dword ptr  4 
  
  
;taking the argument of the function 
.text:004CEA80 000                 mov     eax, [esp+arg_0] 
.text:004CEA84 000                 fld     [esp+arg_0] 
  
;saving values, i think 
.text:004CEA88 000                 push    ebx 
.text:004CEA89 004                 push    esi 
  
moving our pointer to esi and working with it 
.text:004CEA8A 008                 mov     esi, ecx 
.text:004CEA8C 008                 mov     ecx, [esi+14h] 
.text:004CEA8F 008                 mov     [esi+20h], eax 
  
;... continue 
  

I tried to add it to the MTA

  
bool CStaticFunctionDefinitions::SetPedAnimationProgress ( CClientEntity& Entity, const char * szAnimName, float fProgress ) 
{     
    RUN_CHILDREN SetPedAnimationProgress ( **iter, szAnimName, fProgress ); 
  
    if ( IS_PED ( &Entity ) ) 
    { 
        CClientPed& Ped = static_cast < CClientPed& > ( Entity ); 
        CAnimBlendAssociation* pA = g_pGame->GetAnimManager ()->RpAnimBlendClumpGetAssociation ( Ped.GetClump (), szAnimName ); 
  
        if ( pA ) 
        { 
            pA->SetCurrentTime ( fProgress ); 
        } 
    } 
  
    return false; 
} 
  

and

  
void CAnimBlendAssociationSA::SetCurrentTime ( float fTime ) 
{ 
    DWORD DwFunc = 0x4CEA80; // function that actually sets the progress 
    float* fPointer = &fTime; //pointer to fTime, to pass it to function 
    _asm 
    { 
        push    ecx ; saving old ECX value 
        mov     ecx, m_pInterface ; moving "that" pointer to ECX, like the opcode handler 
        push    fPointer ; push the function argument 
        call    DwFunc ; call the function 
        pop     ecx ; and restore the ECX 
    }; 
} 
  

But of course nothing works, and game crashes. May be anyone have any idea? What am i doing wrong?

Link to comment

SetPedAnimationProgress or 0x4CEA80 is possibly part of an undocumented virtual table and it is a THISCALL. It can either be something undocumented in IDA at 0x4CE940 or the interface at CAnimBlendAssociationSA

The proper way to implement it AFAIK is

  
DWORD DwFunc = 0x4CEA80; 
DWORD DwThisInterface = 0x8008135; // not a real pointer to any interface or vtbl 
  
_asm 
{ 
    // pushing and popping is already handled by the call or externally 
    mov ecx, DwThisInterface 
    push fTime // you're already pretty much pushing a reference in inline asm, not need to push a reference 
    call dwFunc 
}; 
  

Link to comment

Yeah! Thank you for the tips, I made it! =) Not really great code, but it works.

Here is the short demonstration of SetPedAnimationProgress function:

And simple script, that i used to test animation progress:

  
Progress = 0.5 
  
function addAnim() 
    setPedAnimation( getLocalPlayer(), "SMOKING", "M_SMKSTND_LOOP") 
end 
addEventHandler( "onClientPlayerSpawn", getLocalPlayer(), addAnim) 
  
function changeProgress(commandName, newProgress) 
    Progress = newProgress / 100; 
end 
addCommandHandler("animprogress", changeProgress) 
  
  
function animRender() 
    setPedAnimationProgress(getLocalPlayer(), "M_SMKSTND_LOOP", Progress) 
end 
addEventHandler("onClientRender", getRootElement(), animRender) 
  

And of cource a patch to MTA.

http://pastebin.com/aC7tLWK3

I have implemented just a client setPedAnimationFunction, I hope someone will implement animation syncing, and i have a stupid question:

  
            /* 
            Here must be something like  
            float fNewTime = pA->GetInterface()->pAnimHierarchy->fTotalTime * fProgress; 
            But only abstract classes avaliable here 
            */ 
            float fNewTime = *(float *)(*(DWORD *)( ((DWORD)(pA->GetInterface())) + 20) + 16) * fProgress; 
  

What to do with this?

Link to comment
I not very good in english, that's why i have documented it in english and russian both.

Your English documentation was good, totally understandable. Function will be useful for scripters, well done and I hope you do more! Well I'm guessing if you managed to make setPedAnimationProgress making other things wouldn't be as hard.

Link to comment
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...