Raised This Month: $12 Target: $400
 3% 

Natives can return arrays in PAWN!


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
klippy
AlliedModders Donor
Join Date: May 2013
Location: Serbia
Old 01-03-2016 , 08:54   Natives can return arrays in PAWN!
Reply With Quote #1

Hello there!
I've got something really interesting for ya!

One syntactic feature of PAWN, that I am sure almost nobody is aware of, is that natives can indeed return arrays! Try compiling the following code:
PHP Code:
native [69]returnArray(); 
Did it compile fine?

I knew this works for quite some time now, but I never really knew how to implement it. I've been searching on Google last year, and I really never found an answer to that. That's why today I decided to do research on my own, and I got some interesting results to show to you!

So, let's get into it. We will test this functionality using the following plugin:
PHP Code:
#include <amxmodx>

#define NAME_LENGTH    32
native [NAME_LENGTH]get_player_name(index);


public 
plugin_init() {
    
register_clcmd("say name""cmdName");
}

public 
cmdName(id) {
    new 
playerName[NAME_LENGTH];
    
playerName get_player_name(id);
    
    
client_print(idprint_chat"Your name is %s."playerName);
    
client_print(idprint_chat"Directly passed in: %s"get_player_name(id));

All we are going to do is print player's own name when they execute the command; very simple. The implementation of get_player_name() (and I'll post full code at the bottom) is as follows:
PHP Code:
#define NAME_LENGTH    32
static cell AMX_NATIVE_CALL get_player_name(AMX *amxcell *params) {
    const 
char *pName MF_GetPlayerName(params[1]);

    
MF_SetAmxString(amxparams[2], pName != nullptr pName ""NAME_LENGTH 1);

    return 
0// Really doesn't matter what we return, but we have to return something

Let's look at the assembly code of cmdName() function from our plugin, which we can get using amxxdump:
Code:
0x90                       PROC              ; public cmdName(id)
0x94                      BREAK              ; nativetest.sma:17
0x98                      BREAK              ; nativetest.sma:18
                                             ; new playerName[32]
0x9C                      STACK  0xFFFFFF80  ; allocate 32 cells
0xA4                   ZERO.pri 
0xA8                   ADDR.alt  0xFFFFFF80 
0xB0                       FILL  0x80        ; 32 cells
0xB8                      BREAK              ; nativetest.sma:19
0xBC                   ADDR.pri  0xFFFFFF80  ; playerName[32]
0xC4                   PUSH.pri 
0xC8                       HEAP  0x80       
0xD0                   PUSH.alt 
0xD4                     PUSH.S  0xC         ; id
0xDC                     PUSH.C  0x4        
0xE4                   SYSREQ.C  0x2         ; get_player_name
0xEC                      STACK  0x8         ; free 2 cells
0xF4                    POP.pri 
0xF8                    POP.alt 
0xFC                       MOVS  0x80       
0x104                      HEAP  0xFFFFFF80 
0x10C                     BREAK              ; nativetest.sma:21
0x110                  PUSH.ADR  0xFFFFFF80  ; playerName[32]
0x118                    PUSH.C  0xC0        ; "Your name is %s."
0x120                    PUSH.C  0x3         ; 0x6500
0x128                    PUSH.S  0xC         ; id
0x130                    PUSH.C  0x10       
0x138                  SYSREQ.C  0x3         ; client_print
0x140                     STACK  0x14        ; free 5 cells
0x148                     STACK  0x80        ; free 32 cells
0x150                  ZERO.pri 
0x154                      RETN
The red colored part is our native call and assignment to playerName[] variable, specifically this line:
PHP Code:
playerName get_player_name(id); 
What we can see here is that playerName[] address gets pushed to stack, but also that the plugin allocates 0x80 bytes (0x80 = 128; 128 / 4 = 32 cells) on HEAP and pushes address of a newly allocated memory block to stack (HEAP opcode returns address in alt), parameters (index) get pushed to stack, parameter count (* 4) gets pushed to stack, and the native gets called. After that, HEAP pointer gets popped off stack to PRI, playerName[] address gets popped to ALT, and then MOVS instruction moves 32 cells from HEAP to playerName[]. Then HEAP instruction just frees previously allocated memory.

If we analyze plugin's stack at the moment our native gets called, it should look similar this:
Code:
<LOWER MEMORY ADDRESS>

argument byte count (0x4)	<- params[0]
index				<- params[1]
pointer to heap			<- params[2], we are looking for this
playerName[] addr		<- this one shouldn't matter at all to us here, it doesn't even have to exist

<HIGHER MEMORY ADDRESS>
We can see here that we need a pointer that is found in params[<param count> + 1], which is params[2] in our case. That pointer points to memory that the plugin has allocated for us to use.
If we had a native that accepts variable number of arguments (like server_print() for example), the pointer would be located at
Code:
params[(params[0] / sizeof(cell)) + 1]
Plugin in action:




Module source code attached.
Attached Files
File Type: zip nativearray_amxx.zip (37.5 KB, 369 views)

Last edited by klippy; 06-10-2016 at 05:37.
klippy is offline
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 01-03-2016 , 14:33   Re: Natives can return arrays in PAWN!
Reply With Quote #2

I don't think it is wise to introduce something like this into AMX Mod X. It will just make it more complicated for people to learn how to write plugins especially if they are not programmers by trade. Basically, it adds unneeded complexity to the syntax.

Also, you would need to make sure that you size "playerName" with NAME_LENGTH instead of hardcoding it to 32.
__________________

Last edited by fysiks; 01-03-2016 at 14:34.
fysiks is offline
klippy
AlliedModders Donor
Join Date: May 2013
Location: Serbia
Old 01-03-2016 , 18:56   Re: Natives can return arrays in PAWN!
Reply With Quote #3

Quote:
Originally Posted by fysiks View Post
I don't think it is wise to introduce something like this into AMX Mod X. It will just make it more complicated for people to learn how to write plugins especially if they are not programmers by trade. Basically, it adds unneeded complexity to the syntax.
Never really wanted this to be introduced to AMXX. This thread's primary purpose is just to be a source of information. I couldn't find how to implement this searching all over Google, not just AlliedModders and AMXX. Someone might find this useful someday. I can see its use with "enum structures".

Quote:
Originally Posted by fysiks View Post
Also, you would need to make sure that you size "playerName" with NAME_LENGTH instead of hardcoding it to 32.
Didn't really understand what you meant by that, because NAME_LENGTH is actually 32 in the code I posted.
klippy is offline
ddhoward
Veteran Member
Join Date: May 2012
Location: California
Old 01-03-2016 , 19:54   Re: Natives can return arrays in PAWN!
Reply With Quote #4

Quote:
Originally Posted by KliPPy View Post
Didn't really understand what you meant by that, because NAME_LENGTH is actually 32 in the code I posted.
Look at the very first line of cmdName().

new playerName[32];

should be

new playerName[NAME_LENGTH];
__________________
ddhoward is offline
klippy
AlliedModders Donor
Join Date: May 2013
Location: Serbia
Old 01-04-2016 , 07:05   Re: Natives can return arrays in PAWN!
Reply With Quote #5

Quote:
Originally Posted by ddhoward View Post
Look at the very first line of cmdName().

new playerName[32];

should be

new playerName[NAME_LENGTH];
Oh right, thank you both for noticing. I have no idea how did I miss that, I was certain I defined it with size of NAME_LENGTH. Will fix when I get to my PC, I'm on my phone now.
klippy is offline
joropito
AlliedModders Donor
Join Date: Mar 2009
Location: pfnAddToFullPack
Old 01-04-2016 , 08:49   Re: Natives can return arrays in PAWN!
Reply With Quote #6

So there's no risk of memory leak? I see the dynamic memory gets freed at end.
__________________

Divide et vinces
approved plugins | steam account

I don't accept PM for support. Just ask on forums.
If you're looking for private work, PM me.
joropito is offline
Send a message via MSN to joropito
klippy
AlliedModders Donor
Join Date: May 2013
Location: Serbia
Old 01-04-2016 , 09:27   Re: Natives can return arrays in PAWN!
Reply With Quote #7

Quote:
Originally Posted by joropito View Post
So there's no risk of memory leak? I see the dynamic memory gets freed at end.
Correct.
klippy is offline
KORD_12.7
Senior Member
Join Date: Aug 2009
Location: Russia, Vladivostok
Old 01-04-2016 , 20:20   Re: Natives can return arrays in PAWN!
Reply With Quote #8

Spoiler
__________________

Vi Veri Veniversum Vivus Vici
Russian Half-Life and Adrenaline Gamer community
KORD_12.7 is offline
Send a message via ICQ to KORD_12.7
thEsp
BANNED
Join Date: Aug 2017
Old 08-08-2019 , 18:09   Re: Natives can return arrays in PAWN!
Reply With Quote #9

This definitely is useful. I find it more useful when knowing that some default AMXX natives can indeed use this.
For example *_to_str natives SHOULD return array/string instead. Sure it might be "limited" (if that's the right term) but still there would be no need to declare a string and use them (which is a bit annoying).

Last edited by thEsp; 08-30-2020 at 16:56.
thEsp is offline
hleV
Veteran Member
Join Date: Mar 2007
Location: Lithuania
Old 08-09-2019 , 08:14   Re: Natives can return arrays in PAWN!
Reply With Quote #10

This is pretty cool.
__________________
hleV is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 18:08.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode