Yeah, I understand all that. What I meant (as a simple example, not actually what I'm trying to do) is this:
Spoiler float myVal = 18.42;const CommandInfo* ceil = g_obseCommands->GetByName("Ceil");// where does myVal go?ceil->execute(paramInfo, arg1, thisObj, arg3, scriptObj, eventList, result, opcodeOffsetPtr);
Now, I was stuck, as I couldn't find any source code for the ExtractArgs function to give me some clues on how the actual argument data is, well, extracted. I had guessed that the actual argument must be somewhere in arg1, but as it was a void*, I couldn't work out what format that data was in.
But I have now found the code for ExtractArgsix, and consequently have been able to get this to work (at least for this simple example), though I would still like some advice from those who know better whether or not this is a safe thing to do, as it's a bit of a hack. From my reading of the code, arg1 is a pointer to the data for the whole calling script, and opcodeOffsetPtr indicates how far into the script data in arg1 lies the argument data for the current script function call. ExtractArgsix then retrieves the function arguments from the script data, taking into account different argument passing mechanisms, such as if the value is simply hardcoded, or is being passed by different variable types etc. The actual format for the argument data consists of 2 bytes for the number of arguments, and then for numeric arguments, 1 byte for the type of format that the number is being given as (hardcoded or variable type), then sizeof(double) or sizeof(UInt32) bytes for the actual argument value if its hardcoded (not a variable), depending on whether its a float or integer. I haven't looked at other argument types as yet, as I'm only interested in numbers at the moment (a cursory glance at passing strings suggested 2 bytes for length of string, followed by the string data in the given size, but I haven't tested it).
So what I did was create my own script data to pass in as arg1, containing the argument data that I want to pass in, and just leave the opcode offset at 0. Again, a bit of a hack, but it did work, at least for this example. Here's the code:
Spoiler UInt8* fArgs = new UInt8[3+sizeof(double)]; UInt16* fArgsNumArgs = (UInt16*)fArgs; *fArgsNumArgs = 1; fArgs[2] = 0x7A; // argument type double double* fArgsVal = (double*)&fArgs[3]; *fArgsVal = 18.42; UInt32 opOffsetPtr = 0; const CommandInfo* ceil = g_obseCommands->GetByName("Ceil"); ceil->execute(paramInfo, fArgs, thisObj, arg3, scriptObj, eventList, result, &opOffsetPtr); delete [] fArgs;
It works. The question is, as long as the data in fArgs is in the right format, is it safe?