AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Snippets and Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=112)
-   -   [TUT] Better Methodmaps tut (https://forums.alliedmods.net/showthread.php?t=260680)

nergal 03-29-2015 14:50

[TUT] Better Methodmaps tut
 
the sourcepawn transitional syntax wiki [ https://wiki.alliedmods.net/SourcePa...itional_Syntax ] horribly explains methodmaps.

This tutorial will aim to give a better understanding, especially to beginners...

In a nutshell, Methodmaps are basically class-like functions for enums

According to Bailopan, "Methodmaps are syntactic transformations only. That is, x.y() on methodmap Z is transformed into a function call that looks like Z_y(x)." - https://forums.alliedmods.net/showpo...&postcount=365

As you can see, methodmaps can help make life a bit easier. Let's begin!

It should be known that methodmaps do not need to be attached to a enum to work. You can have a solo methodmap work by itself, but if you want custom types/tags, then you will be needing an enum.

Because methodmaps are similar to classes, the first part of a methodmap you need is a constructor!

Through messing around with the compiler and such, I've found that Constructors must always have the same name as the Methodmap they're operating from as well as having no identified return type! Constructors can also just do nothing lol! As long as you have a constructor at least.
PHP Code:

methodmap MapMethod
{
    public 
MapMethodint index //this is the constructor!
    
{
        return 
view_as<MapMethod>( index ); /*you must return the data as the methodmap. The data also cannot be an array
or the enum tag you're making the methodmap for or make the constructor do absolutely nothing.*/
    
}


Methodmaps can also have regular, normal functions be used inside them, like so!
PHP Code:

methodmap EntityWithHealth
{
    public 
void SetHealth(int value//normal function
    
{
        
SetEntProp(thisProp_Send"m_iHealth"value);
    }


Adding properties/accessors to your methodmap can make it that much simpler to accessing data. Properties have getters and setters so you can easily set their data and utilize it as soon as possible! properties do not have to have both getters and setters but it should definitely have getters.
PHP Code:

int iMoney 0;
/*
remember that methodmaps are not classes/structs so you need to create globals.
The purpose of the methodmap is to be the only modifier of these global variables
so that the code is more structured and controlled.
*/

methodmap Bank
{
    
property int Money //property!
    
{
        public 
get() { return iMoney; }
        public 
setint value ) { iMoney value; } //property is an int, so the data must be set with an int!
    
}


Then there's inheritance! You can make other methodmaps get the same data and handling as your initial methodmap!

Here's a good example. The parent methodmap has the money property while the child mtm has toys! Since the child mtm inherits from the parent mtm, that means you can use the "Money" accessor from the child mtm!
PHP Code:

int iMoney;
int iToys;
methodmap Parent
{
    
property int Money //has money!
    
{
        public 
get() { return iMoney; }
        public 
setint value ) { iMoney value; }
    }
}
methodmap Child Parent
{
    
property int Toys //has toys AND money :D
    
{
        public 
get() { return iToys; }
        public 
setint value ) { iToys value; }
    }


There's also stuff about inline methods but I've never used them but I just wanted to cover the beginner stuff.

The most important concept of methodmaps is the "this" name. The "this" name basically refers to whatever instance of the methodmap uses the available functions inside it. look at the final code below to see what I mean.

Here's the final product of what most realistic (custom) methodmaps would look like and how they are used!

PHP Code:


int iHealth
[MAXPLAYERS+1];
int iAmmo[MAXPLAYERS+1];
float flSpeed[MAXPLAYERS+1];

methodmap Playur
{
    public 
Playur(int playerindex//constructor
    
{
        return 
view_as<Playur>(playerindex); //make sure you do validity check on players
    
}
     
property int index 
    

        public 
get()                { return view_as<int>(this); } 
    }
    
property int Health
    
{
        public 
get() { return iHealth[this.index]; }
        public 
setint value ) { iHealth[this.index] = value; }
    }
    
property int Ammo
    
{
        public 
get() { return iAmmo[this.index]; }
        public 
setint value ) { iAmmo[this.index] = value; }
    }
    
property float Speed
    
{
        public 
get() { return flSpeed[this.index]; }
        public 
setfloat value ) { flSpeed[this.index] = value; }
    }
    public 
void GiveAmmo(int amount)
    {
        
this.Ammo += amount;
    }
    public 
void RemoveAmmo(int amount)
    {
        
this.Ammo -= amount;
    }
}

public 
void OnClientPutInServer(int client)
{
    
Playur player Playur(client);
    if (
player.Health 1player.Health 100;
    if (
player.Ammo 1player.Ammo 50;
    if (
player.Speed 1.0player.Speed 300.0;


EDIT #1

another thing to introduce to the Methodmaps is the concept of "objectifying" them :)

Here's an example!
PHP Code:

methodmap MapMethod __nullable__
{
    ........


the methodmap is now nullable! Nullable methodmaps actually create objects compared to normal, non-nullable methodmaps!

with a nullable methodmap, you have to use "new" with its constructor!

like so!
PHP Code:

methodmap MapMethod __nullable__
{
    public 
MapMethod() //constructor
    
{
        
//code here
    
}
}

MapMethod Data = new MapMethod(); 

Here's a better full example from one of my own plugins, the Arm Chair General plugin that allows spectators to be more interactive with red or blue team....

PHP Code:

enum {
    
IsGen 0,
    
LeadingTeam
};

#define int(%1)            view_as<int>(%1)

int General[MAX][2];

methodmap Commander
{
    public 
Commander(int userid//constructor: It's less of a headache to use userids
    
{
        if ( 
IsValidClientuserid ) ) {
            return 
view_asCommander >( GetClientUserIduserid ) );
        }
        return 
view_asCommander >(-1);
    }

    
property int index
    
{
        public 
get()            { return GetClientOfUserIdint(this) ); }
    }
    
property int bIsGeneral
    
{
        public 
get()            { return Generalthis.index ][ IsGen ]; }
        public 
setint val )        { Generalthis.index ][ IsGen ] = val; }
    }
    
property int iLeadingTeam
    
{
        public 
get()            { return Generalthis.index ][ LeadingTeam ]; }
        public 
setint val )        { Generalthis.index ][ LeadingTeam ] = val; }
    }
}; 

Creating a methodmap out of natives!

.inc file
PHP Code:

methodmap NativeMap
{
    public 
native NativeMap();

    
property int MyIntProperty {
        public 
native get();
        public 
native set(const int val);
    }

    public 
native void MyMethodFunc();


implementation in the plugin that's exporting the native-based methodmap
PHP Code:

public APLRes AskPluginLoad2(Handle myselfbool latechar[] errorint err_max)
{  
    
CreateNative("NativeMap.NativeMap"Native_NativeMapInstance);

    
CreateNative("NativeMap.MyIntProperty.get"Native_GetMyIntProperty);
    
CreateNative("NativeMap.MyIntProperty.set"Native_SetMyIntProperty);
    
CreateNative("NativeMap.MyMethodFunc"Native_MyMethodFunc);
    
    return 
APLRes_Success;
}

public 
int Native_NativeMapInstance(Handle pluginint numParams)
{
    return 
GetNativeCell(1);
}
public 
int Native_GetMyIntProperty(Handle pluginint numParams)
{
    return 
Health[GetNativeCell(1)];    /* GetNativeCell(1) IS ALWAYS THE "this" parameter */
}
public 
int Native_SetMyIntProperty(Handle pluginint numParams)
{
    
Health[GetNativeCell(1)] = GetNativeCell(2);
}
public 
int Native_MyMethodFunc(Handle pluginint numParams)
{
    
CallBackFunc(GetNativeCell(1), GetNativeCell(2));
    
// Remember that GetNativeCell(1) is always the "this" parameter aka the first argument



Chdata 03-29-2015 15:00

Re: [TUT] Better Methodmaps tut
 
(int i = 0; i < 9; i++)

(int i = 0; i < 10; i++)

nergal 03-29-2015 15:28

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by chdata (Post 2279537)
(int i = 0; i < 9; i++)

(int i = 0; i < 10; i++)

(╯ ͡° ͜ʖ ͡°)╯︵ /(.□ . \)

psychonic 03-29-2015 16:03

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by nergal (Post 2279534)
the sourcepawn transitional syntax wiki [ https://wiki.alliedmods.net/SourcePa...itional_Syntax ] horribly explains methodmaps.

It's a wiki. Feel free to edit or add to it.

(You can use your forum username and password to log in).

nergal 03-29-2015 17:31

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by psychonic (Post 2279561)
It's a wiki. Feel free to edit or add to it.

(You can use your forum username and password to log in).

my gut says I shouldn't touch the wiki and accept whatever the wiki tells me as God.

asherkin 03-29-2015 18:03

Re: [TUT] Better Methodmaps tut
 
A huge focus of this is on properties... but none of your properties have anything backing them.

nergal 03-29-2015 18:50

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by asherkin (Post 2279615)
A huge focus of this is on properties... but none of your properties have anything backing them.

not quite understanding what you mean.

I'm assuming you're saying that there's no real variables? They're just examples.

Plus we should talk about this more so others can understand more where I'm making a mistake

TnTSCS 03-30-2015 03:32

Re: [TUT] Better Methodmaps tut
 
I will be watching this thread - Methodmaps is a completely foreign concept for me atm.

Nerus 12-26-2015 09:59

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by TnTSCS (Post 2279738)
I will be watching this thread - Methodmaps is a completely foreign concept for me atm.

OK, there is other method to create something similar to class ?

Regards,
Nerus

nosoop 12-26-2015 11:15

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by nergal (Post 2279637)
I'm assuming you're saying that there's no real variables? They're just examples.

Here's what I (very sleepily) think might throw people off:
  • First example: The variable name index is vague. I'm assuming entity index based on context, but there's also array indices. MethodMap is also vague and I'd recommend replacing it with a more descriptive name for that particular example, like DamageableEntity.
  • Second example: I'd say add the constructor from the previous constructor to this snippet for completeness' sake, and explain that this basically just refers to the value passed into the constructor (which is why it was only returned with a different view; syntactic transformation only, remember!).
  • Third through fifth: Methodmaps have no member variables; just having iMoney, etc. show up out of nowhere leaves questions of implementation (which I can't think of a simple answer to except by saying "just pretend methodmaps don't exist and use some kind of array / data structure like you would've instead"). I'd point to the SourceMod transitional helpers for some examples of the "pass a variable and use 'wrapper' functions to manipulate them in a readable fashion", as well as the new API documentation for DataPacks (note: the x() = y binding was removed), StringMaps, etc. to show how they're used when you're working with Handles.
  • Eighth: int(x) doesn't exist in stock SourceMod?
Can't comment on __nullable__ as I'm not familiar with the specifics of that, but I'm sure they don't actually create objects (i.e., they won't magically have member variables).

Quote:

Originally Posted by Nerus (Post 2376429)
OK, there is other method to create something similar to class?

Not quite natively. As mentioned, you have to store those "member" variables somewhere. The built-in StringMaps or Dynamic would work, but you'll be working with Handles at that point.

nergal 12-26-2015 12:23

Re: [TUT] Better Methodmaps tut
 
ok there, the examples have real backing fields now.

I also modified the custom example that most plugins would likely use.

CSGOT 02-07-2016 11:07

Re: [TUT] Better Methodmaps tut
 
Nice Tutorial.
This really helped me alot.
Thanks OP

nergal 02-07-2016 12:59

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by CSGOT (Post 2390819)
Nice Tutorial.
This really helped me alot.
Thanks OP

no problem. If you have anymore questions, please don't hesitate to ask.

StSatan 02-09-2016 05:12

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by nergal (Post 2279534)

PHP Code:


int iHealth
[MAXPLAYERS+1];
int iAmmo[MAXPLAYERS+1];
float flSpeed[MAXPLAYERS+1];

methodmap Player
{
    public 
Player(int playerindex//constructor
    
{
        return 
view_as<Player>(playerindex); //make sure you do validity check on players
    
}
     
property int index 
    

        public 
get()                { return view_as<int>(this); } 
    }
    
property int Health
    
{
        public 
get() { return iHealth[this.index]; }
        public 
setint value ) { iHealth[this.index] = value; }
    }
    
property int Ammo
    
{
        public 
get() { return iAmmo[this.index]; }
        public 
setint value ) { iAmmo[this.index] = value; }
    }
    
property float Speed
    
{
        public 
get() { return flSpeed[this.index]; }
        public 
setfloat value ) { flSpeed[this.index] = value; }
    }
    public 
void GiveAmmo(int amount)
    {
        
this.Ammo += amount;
    }
    public 
void RemoveAmmo(int amount)
    {
        
this.Ammo -= amount;
    }
}

public 
void OnClientPutInServer(int client)
{
    
Playur player Player(client);
    if (
player.Health 1player.Health 100;
    if (
player.Ammo 1player.Ammo 50;
    if (
player.Speed 1.0player.Speed 300.0;



So in "normal" situation we can simply increase array:

PHP Code:

iHealth[index]++ 

or decrease

PHP Code:

iHealth[index]-- 

but with using methodmaps we can't type:

PHP Code:

index.Health++ 

am I right?

WildCard65 02-09-2016 08:14

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by StSatan (Post 2391340)
So in "normal" situation we can simply increase array:

PHP Code:

iHealth[index]++ 

or decrease

PHP Code:

iHealth[index]-- 

but with using methodmaps we can't type:

PHP Code:

index.Health++ 

am I right?

Nope.
Basically, what happens is SP will get the return value from the get() method and increment that by one, then it will call the set() method with the new value.
example:
PHP Code:

T.LOL.set(tT.LOL.get(t)++); //T is methodmap, LOL is property(type int), t is variable(type T) 


humbugtheman 02-21-2016 19:19

Re: [TUT] Better Methodmaps tut
 
Thanks for the tut - very clear!

nergal 05-27-2016 13:45

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by humbugtheman (Post 2395489)
Thanks for the tut - very clear!

No problem. If you have any questions, don't hesitate to ask!

sdz 05-27-2016 15:07

Re: [TUT] Better Methodmaps tut
 
Don't understand the tut at all honestly.
See this is why I just stay away from newdecls.

nergal 05-27-2016 18:49

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by EasSidezz (Post 2422550)
Don't understand the tut at all honestly.
See this is why I just stay away from newdecls.

what part do you not understand?

sdz 05-27-2016 23:27

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by nergal (Post 2422616)
what part do you not understand?

It's not you, it's me.

Neuro Toxin 05-28-2016 03:41

Re: [TUT] Better Methodmaps tut
 
Are you breaking up with me?

nergal 05-28-2016 19:38

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by EasSidezz (Post 2422647)
It's not you, it's me.

ok, what part are you not understanding? ° ͜ʖ °

Chief149 06-09-2016 01:37

Re: [TUT] Better Methodmaps tut
 
The only part I don't fully understand is when doing stuff like inheriting an ArrayList in a methodmap.

This one guy did upload a "Dynamic" plugin which is designed to allow developers to make the closest thing to objects. Well I figured out it would likely be simpler to just make a methodmap and have it inherit ArrayList like such:

Code:

methodmap BDoor < ArrayList
{
    public BDoor(int doorid)
    {
        ArrayList bdoor = new ArrayList();
        bdoor.Push(doorid); //index 0 is doorid
        bdoor.Push(0); //index 1 holds the locked state
        return view_as<BDoor>(bdoor);
    }
   
    property int doorid
    {
        public get()
        {
            return this.Get(0); //where the door id is stored
        }
    }

    property bool locked
    {
        public get()
        {
            return this.Get(1); //where the lock state is stored
        }
   
        public set(bool isLocked)
        {
            this.Set(1, isLocked);
            if(isLocked)
                AcceptEntityInput(this.doorid, "Lock");
            else
                AcceptEntityInput(this.doorid, "Unlock");
        }
    }
}

I mean, sure it means that basically every custom methodmap is technically an arraylist where someone could just add in code to modify any of the elements, but that's kind of the case with the Dynamic class that one guy made on here. It's just really simple I guess.

Neuro Toxin 06-09-2016 05:24

Re: [TUT] Better Methodmaps tut
 
Dynamic addresses a few concerns around simply inheriting ArrayList.

1. Blocksize: If you set a blocksize to accommodate for Strings your waisting memory for int/bool/float values.

2. It's nice to share methodmaps between plugins: however; if one plugin orders the indicies differently your corrupting data.

You'd be best to inherit to a trie memory wise. A membername lookup via trie is really fast (dynamic does this internally).

Once again Dynamic is designed to address a few issues when using a trie.

1. You might want to iterate members, this is impossible using a trie alone

2. Dynamic members are typed. Dynamic knows the type of each member and supports full type conversion for all the base pawn tags.

Everything dynamic does is for a good reason. It can do 100k member reads in less than .1 seconds. So you shouldnt be concerned about performance.

I have dynamic classes that have 100+ members and some members running on each frame / usercmd with no issues at all.

Powerlord 06-09-2016 22:59

Re: [TUT] Better Methodmaps tut
 
Quote:

Originally Posted by Neuro Toxin (Post 2426041)
1. You might want to iterate members, this is impossible using a trie alone

That hasn't been true since SM 1.7 came out.

You can iterate over a Trie by getting by getting a snapshot of its keys using CreateTrieSnapshot or StringMap's .Snapshot

Neuro Toxin 06-10-2016 00:22

Re: [TUT] Better Methodmaps tut
 
Interesting.

Im going to have a play and do some benchmarking against dynamics current iteration support.

Love your work mr lord.


All times are GMT -4. The time now is 22:06.

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