Jump to content

Opcodes. Variable number of arguments


Lev_Landau

Recommended Posts

You'll need to do that in somewhat a manual way.

First, you'll need a point of reference to how many extra parameters you'll have, in the case of those opcodes you have the "number of params" and the "number of formating".
Then you'll just need to collect the number of parameters needed using the respective SDK functions (CLEO_GetFloatOpcodeParam, CLEO_GetIntOpcodeParam, etc etc).

Now, how do you know what parameter type it is, a string, int, float...? Use CLEO_GetOperandType and check the result. The SDK should have a enum with the operand types but if it doesn't you can look here on the datatypes table.

Now, what if you don't have a number of parameters to collect but you still want to collect all extra parameters, just like 004F? Simple, the last operand type will be 0x0, it singalizes the end of the extra parameters list.

So, here we go with a example:

/* bla */ opcode_7FFF(/* bla bla bla */){    int operand;    // bla bla bla     while(operand = CLEO_GetOperandType(thread)) // While not the end of the extra parameters    {        switch(operand)        {            // Check out the operand type and do your stuff            // Put your cases here <>        }    }}
Edited by LINK/2012
Link to comment
Share on other sites

Most trivial options:

Option 1: Let the 'Log' function handle the parameters collection

Option 2: Store the parameters + parameter type on an array and send to the logging func.

 

I guess the option 1 is better, option 2 looks dirty.

Edited by LINK/2012
Link to comment
Share on other sites

You could take the array parameter flags, check out here

But really, I don't think you should, the game itself don't care about what you're sending, it expects you to be sending what it wants.

For example, 0001 (WAIT), the game expects a integer, right? What if you send a float (e.g. WAIT 1.0)? Well, what will happen is that it will still collect a integer and then will WAIT 0x3F800000 (0x3F800000 is the binary representation of the floating point 1.0)

So really, just parse your formats, if you come up with an '%f' tell CLEO to collect a float, with a '%s', collect a string, and so on.

 

Here's a simple example:

 

void Log(const char* format, CScriptThread* thread){    for(; *format; ++format)    {        if(*format == '%')        {            if(format[1] == 'f')            {                // Collect a float and sprintf into your buffer, or print it already, dunno            }            else if /* and so on */ {}        }        else { /**/ }    }}/**/ opcode_7FFF(/**/){    Log(CollectStringParameter(thread), thread);    // Skip unused params if you want, CLEO has a SDK func to skip unused params.}
Edited by LINK/2012
Link to comment
Share on other sites

CLEO SDK can't handle such opcodes. You need to do operations with CScriptThread data manually.

Link to comment
Share on other sites

 

CLEO SDK can't handle such opcodes. You need to do operations with CScriptThread data manually.

What may handle them? There are native opcodes with variable number of parameters and I also found some custom opcodes, that accept variable number of parameters as well (namely SAMPFUNCS)

 

 

 

Simply check:

if( *thread->ip != NULL )

before trying to get a parameter.

 

However, the purpose of the 'null data type' is for the end of an argument list - not for the end of "variable number of arguments" - that is strictly a SB reference and it's common to confuse it's simplifications of what was once a more complex language. In the original engine it's never used for anything other than transmitting parameters to another script. CLEO actually never does any different - for most opcodes (CALL and RET) they are being used in pretty much the same way. All other times, the number of arguments and more importantly the types have to be known somehow. Pretty pointless trying to get everything when you know exactly what you need.

 

Anyway, CLEO 4 has already done this and the source code is available anyway, but here's the specific function of interest: https://pastebin.com/1nSRi0zi

 

As you can see, no need for getting a variable number of arguments, but you can call SkipOpcodeParams afterwards if you want to allow something that shouldn't happen.

 

The variant for sscanf-style operations might be of interest, too, but I'll just post it here:

 

int *result = (int *)GetScriptParamPointer(thread);  SCRIPT_VAR *ExParams[35];  // read extra params  for(int i = 0; i<35; i++)  {   if(*thread->ip)   {    ExParams[i] = GetScriptParamPointer(thread);    cExParams++;   }   else ExParams[i] = nullptr;  }  ++thread->ip;  *result = sscanf(src, format,   /* extra parameters (will be aligned automatically, but the limit of 35 elements maximum exists) */     ExParams[0], ExParams[1], ExParams[2], ExParams[3], ExParams[4], ExParams[5],   ExParams[6], ExParams[7], ExParams[8], ExParams[9], ExParams[10], ExParams[11],   ExParams[12], ExParams[13], ExParams[14], ExParams[15], ExParams[16], ExParams[17],   ExParams[18], ExParams[19], ExParams[20], ExParams[21], ExParams[22], ExParams[23],   ExParams[24], ExParams[25], ExParams[26], ExParams[27], ExParams[28], ExParams[29],   ExParams[30], ExParams[31], ExParams[32], ExParams[33], ExParams[34]);
Link to comment
Share on other sites

How you need to do that manually? CLEO_GetOperandType returns the current byte (and thus the datatype) without moving PC.

Link to comment
Share on other sites

  • 2 weeks later...

Opcodes with an undefined amount of parameters 'terminate' the param list with 00, are you handling this in your code? If you don't, it'll next be executed as a part of opcode ID and therefore crash.

Edited by Silent
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 1 User Currently Viewing
    0 members, 0 Anonymous, 1 Guest

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.