CallLocalFunction indirectly using #emit
#1

I want to call a local function indirectly with arguments without inside of a argument function.
What i mean is, i will store the arguments into a variable with a MAX value.

After certain time interval, i will call "CallLocalFunction" with all the stored arguments pushed in.

But i am not that good with amx assembly, so i guess if you can help?

// Code explanation
pawn Код:
#define MAX_ARGS (10)
new array[MAX_ARGS][100];
new fmat[MAX_ARGS];

function(format[], {Float, _}:...)
{
    fmat = format;
    array = args; // store all the arguments in this array
}

timer()
{
    CallLocalFunction("oncall", fmat, array);
}

public OnCall(id, string...)
{

}

I was successful in performing the code for only integer type arguments but i can't figure out for Float and String.
Reply
#2

Quote:
Originally Posted by Gammix
Посмотреть сообщение
I was successful in performing the code for only integer type arguments but i can't figure out for Float and String.
Float values.
Compiler converts float values to int (IEEE 754 standart). You need convert your float to int (use float()).
Strings.
You need use push.adr/addr.pri/addr.alt instruction.
Reply
#3

Quote:
Originally Posted by VVWVV
Посмотреть сообщение
Float values.
Compiler converts float values to int (IEEE 754 standart). You need convert your float to int (use float()).
Strings.
You need use push.adr/addr.pri/addr.alt instruction.
That is not the problem. The issue is pushing all the arguments in different types into stack without messing addresses.

I don't know what i am doing wrong here, as i said before, not a pro in amx assembly.
pawn Код:
new function[(4+MAX_TIMERS)];
                    format(function, sizeof (function), "tmr_%i", i);

                    static fmat[MAX_TIMER_ARGS];
                    strunpack(fmat, g_TimerArgsType[i]);
                   
                    new n = strlen(fmat);
                    if (n <= 0)
                    {
                        CallLocalFunction(function, "", "\1");
                        continue;
                    }

                    static dest[MAX_TIMER_ARGS_VALUE];
                    static frm[MAX_TIMER_ARGS];
                    for (new x = (n-1), y = ((x+2) * 4), z; x >= 0; x--, y -= 4, z++)
                    {
                        switch (fmat[x])
                        {
                            case 'i', 'd':
                            {
                                strunpack(dest, g_TimerArgs[i][x]);
                                new val = strval(dest);
                                #emit PUSH.adr  val
                            }

                            case 'f':
                            {
                                strunpack(dest, g_TimerArgs[i][x]);
                                new Float:val = floatstr(dest);
                                #emit PUSH.adr  val
                            }

                            case 's':
                            {
                                strunpack(dest, g_TimerArgs[i][x]);
                                #emit PUSH.adr  dest
                            }
                        }
                        frm[z] = fmat[x];
                    }
                    #emit PUSH.adr      frm
                    #emit PUSH.adr      function
                   
                    n += 2;
                    n *= 4;
                    #emit PUSH.s        n
                    #emit SYSREQ.c      CallLocalFunction

                    #emit LCTRL         4
                    #emit LOAD.S.ALT    n
                    #emit ADD.C         4
                    #emit ADD
                    #emit SCTRL         4
g_TimerArgsType is a string storing the format string (e.g. "ddss").
g_TimerArgs stores a bunch of string with the values of arguments (all are stored as strings) and then converting accordingly before pushing into stack.



EDIT: I made a bit modification of fmat, need to reverse it's order as well.
Reply
#4

Bump

Its weird because if i manually push arguments (declaring my own set of variable which is now how many are they in number), the callback is called successfully.
Reply
#5

So like this but, adding to CallLocal..
Quote:
Originally Posted by Dayrion
Посмотреть сообщение
SendClientMessage/SendClientMessageToAll with parameters.
PHP код:
//------------------------------------------------------------------------------------------------

stock SCMF(playerid,color,fstring[],{Float_}:...)
{
   new 
n=(numargs()-3)*4;
   if(
n)
   {
      new 
message[128],arg_start,arg_end;
      
#emit CONST.alt                fstring
      #emit LCTRL                    5
      #emit ADD
      #emit STOR.S.pri               arg_start
      #emit LOAD.S.alt               n
      #emit ADD
      #emit STOR.S.pri               arg_end
      
do
      {
         
#emit LOAD.I
         #emit PUSH.pri
         
arg_end-=4;
         
#emit LOAD.S.pri           arg_end
      
}
      while(
arg_end>arg_start);
      
#emit PUSH.S                   fstring
      #emit PUSH.C                   255
      #emit PUSH.ADR                 message
      
n+=4*3;
      
#emit PUSH.S                   n
      #emit SYSREQ.C                 format
      
n+=4;
      
#emit LCTRL                    4
      #emit LOAD.S.alt               n
      #emit ADD
      #emit SCTRL                    4
      
return SCM(playerid,color,message);
   }
   else return 
SCM(playerid,color,fstring);
}

//------------------------------------------------------------------------------------------------ 
Or am I wrong?
Reply
#6

Quote:
Originally Posted by Meller
Посмотреть сообщение
So like this but, adding to CallLocal..



Or am I wrong?
No thats loading the arguments from the function, i have already done that in Timer_Start, i am having problem in pushing them into CallLocalFunction (don't know what's wrong) from a different place (in a different callback) and the result i get from the call is some weird numbers.
Reply
#7

PHP код:
CallLocalFunction("oncall"fmat, array); 
on this call if fmat had "d" for example whole arry will be assigned to it except if you put , and another var
so if I am not wrong you can do it by this way
PHP код:
#define MAX_ARGS (10)
new array[MAX_ARGS][100];
new 
numargsz;
new 
fmat[MAX_ARGS];
function(
format[], {Float_}:...)
{
    
fmat format;
    
numargs =  numargs()-1;
    array = 
args// store all the arguments in this array
}
timer()
{
    if(
numargsz == 1)
    {
       
CallLocalFunction("oncall"fmat, array[0]);
    }
    if(
numargsz == 2)
    {
       
CallLocalFunction("oncall"fmat, array[0], array[1]);
    }
    
// and so on....
}
public 
OnCall(idstring...)
{

Reply
#8

Quote:
Originally Posted by jlalt
Посмотреть сообщение
PHP код:
CallLocalFunction("oncall"fmat, array); 
on this call if fmat had "d" for example whole arry will be assigned to it except if you put , and another var
so if I am not wrong you can do it by this way
PHP код:
#define MAX_ARGS (10)
new array[MAX_ARGS][100];
new 
numargsz;
new 
fmat[MAX_ARGS];
function(
format[], {Float_}:...)
{
    
fmat format;
    
numargs =  numargs()-1;
    array = 
args// store all the arguments in this array
}
timer()
{
    if(
numargsz == 1)
    {
       
CallLocalFunction("oncall"fmat, array[0]);
    }
    if(
numargsz == 2)
    {
       
CallLocalFunction("oncall"fmat, array[0], array[1]);
    }
    
// and so on....
}
public 
OnCall(idstring...)
{

Nope, you cannot push string as integer or float. And the issue is not that, the issue is how i am supposed to get the arguments in the right address.

(if you see, i am very able to identify the value's type and push them in the for loop)

Here is an example how it works:
pawn Код:
new fmat[] = "dd"; // say i stored this
new val1 = 5, val2 = 6; // say i stored this as well
new callback[] = "OnCall"; // this the function name which will be called

#emit PUSH.adr val2
#emit PUSH.adr val1
#emit PUSH.adr fmat
#emit PUSH.adr callback
#emit PUSH.c 16 //(4*4)
#emit SYSREQ.c CallLocalFunction
^^ The above code very nicely executes.

This is sort of the same way i am trying in the real code i am working on. But the result is not fruitful. I don't know why the addresses gets fucked up while i am pushing the values in CallLocalFunction's argument list.
Reply
#9

It's been a while since I dabbled with pcode. Check this out:
pawn Код:
#include <a_samp>
#define _inc_a_samp

main()
{
    static val2[] = "Hello world";
    new fmat[] = "ds";
    new val1 = 5;
    new callback[] = "Hello";

    CallLocalFunction(callback, fmat, val1, val2);
}

forward Hello(a, b[]);
public Hello(a, b[]) {
    printf("%d %s", a, b);
}
With -a, interesting us excerpt:
pawn Код:
; line b
break   ; a0
const.pri 0
push.pri
;$par
addr.pri fffffff0
push.pri
;$par
addr.pri fffffff4
push.pri
;$par
addr.pri ffffffd8
push.pri
;$par
push.c 10
sysreq.c 0  ; CallLocalFunction
stack 14
See this? Static variables are stored on heap, same as global ones, not stack (I'm taking about your "static dest[MAX_TIMER_ARGS_VALUE]"). PUSH.addr is nothing more than FRM + offset, but what you need is PUSH.C with offset.


Also worth noting I guess:
pawn Код:
for (new x = (n-1), y = ((x+2) * 4), z; x >= 0; x--, y -= 4, z++)
{
    switch (fmat[x])
    {
        case 'i', 'd':
        {
            strunpack(dest, g_TimerArgs[i][x]);
            new val = strval(dest);
            #emit PUSH.adr  val
        }

        case 'f':
        {
            strunpack(dest, g_TimerArgs[i][x]);
            new Float:val = floatstr(dest);
            #emit PUSH.adr  val
        }

        case 's':
        {
            strunpack(dest, g_TimerArgs[i][x]);
            #emit PUSH.adr  dest
        }
    }
    frm[z] = fmat[x];
}
There happens quite a lot of function calling, watch out to not corrupt the stack before strunpack (on second thought, I don't think anything bad will happen, just clear the stack with STACK after calling the SYSREQ.C)
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)