#1

Hello!
I've returned to SA:MP after quite some time now and I checked a script and found this.
PHP Code:
stock SendClientMessageEx(playeridcolor, const text[], {Float_}:...)
{
    static
        
args,
        
str[144];
    if ((
args numargs()) == 3)
    {
        
SendClientMessage(playeridcolortext);
    }
    else
    {
        while (--
args >= 3)
        {
            
#emit LCTRL 5
            #emit LOAD.alt args
            #emit SHL.C.alt 2
            #emit ADD.C 12
            #emit ADD
            #emit LOAD.I
            #emit PUSH.pri
        
}
        
#emit PUSH.S text
        #emit PUSH.C 144
        #emit PUSH.C str
        #emit PUSH.S 8
        #emit SYSREQ.C format
        #emit LCTRL 5
        #emit SCTRL 4
        
SendClientMessage(playeridcolorstr);
        
#emit RETN
    
}
    return 
1;

From the usages of it, I see that this function is used to send messages with "variables" instead of formatting it and then sending the formatted message.

I just don't get what this #emit does. I tried to search for an emit preprocessor for C/C++(so I can get a general answer rather than a samp-related one), but can't find any results(There is a _emit keyword, which is not what this is).

It would be greatly appreciated if someone can briefly explain to me what that is. No complicated topics since I am just 14.

Have a nice day.

EDIT: If there is a "non-emit" alternative to do this, please let me know.
Reply
#2

#emit is a way to write in-line P-Code/Bytecode (Pawn's compiled "Assembly" so to speak).

This is often done to either bypass limitations of the language, obsfucate code, increase execution speed (by hand-assembling specific code faster than the compiler would) or all of the above.

In this case I think it is bypassing a limitation of how arguments are managed by the Pawn language, as it seems to be pushing a variable amount of arguments to the stack in that while, which would not be possible by writing it properly.

Quote:

#emit PUSH.S text
#emit PUSH.C 144
#emit PUSH.C str
#emit PUSH.S 8
#emit SYSREQ.C format

In this portion of the code, the parameters "text", "144", "str", and "8" are pushed to the stack to be used as variables, before doing a system call to the sa-mp server to run the "format" function with these.

The Pawn Language Official Document by CompuPhase has a small bit where these preprocessor directives are explained, including #emit

TL-DR: All of those emits are just for a format(), but it cannot be done without emits as it was done this way in order to be able to send a variable amount of arguments
Reply
#3

A non-emit alternative:

Code:
stock bool:FALSE = false;
new scmExStr[144];
#define SendClientMessageEx(%0,%1,%2,%3) do{format(scmExStr,144,%2,%3);SendClientMessage(%0,%1,scmExStr);}while(FALSE)
Note that this (obviously) will not work this way:
Code:
if (!statement)
    return SendClientMessageEx...
As it's a macro/define, this would be translated to "return do{format...".
Also if you just use parameters playerid, color, message it this ..Ex function would fail as it wouldn't be recognised by the pre-processor.
Also you may have noticed the "stock bool:FALSE = false". The do statement must run once (hence the while(false)). Using "false" you'd get an error (empty statement I believe, indu---something--- code). By defining stock FALSE you still use the same statement except the compiler doesn't recognise it as an empty statement. So in short, just a way to make the compiler happy)

Even though it doesn't matter that much with systems these days, this is better for runtime speeds. Just go with whatever you desire, this is just what I prefer.
Reply
#4

Quote:
Originally Posted by Kwarde
View Post
A non-emit alternative:

Code:
stock bool:FALSE = false;
new scmExStr[144];
#define SendClientMessageEx(%0,%1,%2,%3) do{format(scmExStr,144,%2,%3);SendClientMessage(%0,%1,scmExStr);}while(FALSE)
Note that this (obviously) will not work this way:
Code:
if (!statement)
    return SendClientMessageEx...
As it's a macro/define, this would be translated to "return do{format...".
Also if you just use parameters playerid, color, message it this ..Ex function would fail as it wouldn't be recognised by the pre-processor.
Also you may have noticed the "stock bool:FALSE = false". The do statement must run once (hence the while(false)). Using "false" you'd get an error (empty statement I believe, indu---something--- code). By defining stock FALSE you still use the same statement except the compiler doesn't recognise it as an empty statement. So in short, just a way to make the compiler happy)

Even though it doesn't matter that much with systems these days, this is better for runtime speeds. Just go with whatever you desire, this is just what I prefer.
This is a very creative approach, I wouldn't have thought of using a macro for this. +rep
Reply
#5

Thanks, both of you.

Where can I learn about this(outside of samp)?
Reply
#6

https://sampforum.blast.hk/showthread.php?tid=308670
https://sampforum.blast.hk/showthread.php?tid=570930
https://sampforum.blast.hk/showthread.php?tid=591705

For more, read about Assembly x86
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)