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

Classes/Objects in SourcePawn


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Headline
SourceMod Moderator
Join Date: Mar 2015
Old 06-22-2018 , 00:01   Classes/Objects in SourcePawn
Reply With Quote #1

Introduction:
It's true that sourcepawn doesn't have objects, but that doesn't mean we can't make a construct that really seems like an object. This post will serve as a simple tutorial around how to do just that. While this method has been known for a while and is nothing new, I am writing this for those who are either unfamiliar with the language or haven't seen this before. Furthermore, I believe constructs like this can really help clean up lots of the code that floats around here and makes it easier to re-use code.

If you're unfamiliar with classes or object-oriented programming, you should read up on that before continuing.


Concept:
Since 1.7, methodmaps have existed in the language which allows us to attribute methods to a tag or type. With this possible, we are able to take an existing concept and add our own methods and define our own meanings to them. More on this later...

A StringMap is a data structure which attributes a key with a certain value. To access a value, you need the key. The key can be any string, and we can store any piece of data along side it. A StringMap can be visualized below with the left column being the key, and the right column being the value.



With these two concepts combined, we can take the base StringMap and add methods in it to grab our data for us, so all we have to do in the end is a method call. Here's an example of us creating a "Dog" object which holds it's name, age, and sex


Implementation:
PHP Code:
methodmap Dog StringMap {
    public 
Dog() {
        return 
view_as<Dog>(new StringMap()); // We'll create a StringMap, but call it a dog.
    
}
    
    public 
void SetName(const char[] name) {
        
this.SetString("name"name);
    }
    
    public 
void GetName(char[] bufferint maxlen) {
        
this.GetString("name"buffermaxlen);
    }
    
    public 
void SetAge(int age) {
        
this.SetValue("age"age);
    }
    
    public 
int GetAge() {
        
int age;
        
this.GetValue("age"age);
        return 
age;
    }
    
    public 
void SetSex(char sex) {
        
this.SetValue("sex"sex);
    }
    
    public 
char GetSex() {
        
char sex;
        
this.GetValue("sex"sex);
        return 
sex;
    }

Now later in our code, we can use the new Dog class like this.

PHP Code:
Dog dog = new Dog();
dog.SetName("Jack");
dog.SetAge(13);
dog.SetSex('M');


// use dog somehow, get the values back, do whatever
delete dog// CLOSE THE HANDLE 

This is a relatively easy concept for intermediate programmers, but for beginners this can seem daunting and that's fine. If you have questions feel free to ask below or even dabble in other OOP languages to get a feel for what object-oriented programming is good at accomplishing.


To finalize this I'd like to say that other sourcemod/sourcepawn projects have existed to accomplish this like Dynamic or my own SMObjects (which is basically the same as StringMap), but both are not-optimal and will only cause more problems or dependencies that are completely unnecessary. Using this method is faster, supported in core sourcemod, and requires no additional dependencies that other solutions will require.

Hope you learned something, if not, consider helping me make this tutorial better.

Last edited by Headline; 07-03-2018 at 20:27.
Headline is offline
ddhoward
Veteran Member
Join Date: May 2012
Location: California
Old 06-30-2018 , 00:08   Re: (fake) Classes/Objects in SourcePawn
Reply With Quote #2

Quote:
Originally Posted by Neuro Toxin View Post
You could also use Dynamic along with it's Class Builder.

Dynamic also has a Basic methodmap which uses a StringMap
Dynamic is mentioned at the bottom of the OP.
__________________
ddhoward is offline
nosoop
Senior Member
Join Date: Aug 2014
Old 06-30-2018 , 22:51   Re: (fake) Classes/Objects in SourcePawn
Reply With Quote #3

I'd probably go with the native KeyValues in most cases myself. It's a bit slower than StringMaps (2.5x IIRC), but you get weak typing with every single type it supports (which, depending on your viewpoint, may be a pro or a con), you get nested maps, but more importantly, you get serialization capabilities through exporting / importing. There are a few KV-specific quirks you need to be aware of (subkey access, case insensitivity), but there's nothing to worry about otherwise.

Heck, I wrote my server's web API backend with optional KeyValues output instead of JSON for server interop; it's quite nice.

StringMaps are great for temporary mappings that should last as long as the plugin, but the serialization is very much DIY.

Only thing I feel that we're really missing is a library that does fully custom properties that are linked to entity lifetimes.
__________________
I do TF2, TF2 servers, and TF2 plugins.
AlliedModders Releases / Github / TF2 Server / Donate (BTC / BCH)

Last edited by nosoop; 07-01-2018 at 00:49.
nosoop is offline
hmmmmm
Senior Member
Join Date: Mar 2017
Location: ...
Old 07-01-2018 , 03:30   Re: (fake) Classes/Objects in SourcePawn
Reply With Quote #4

Quote:
Originally Posted by nosoop View Post
Only thing I feel that we're really missing is a library that does fully custom properties that are linked to entity lifetimes.
CustomKeyValues

Bad name since its actually implemented as a nested StringMap but thats pretty much what it does. The main aim was to get data from maps/mappers that they can implement as KeyValues from hammer, but you can also set keys/values from the plugin side. One issue is that you can only get these values as strings, which I was planning on changing at some point but never did.
hmmmmm is offline
nosoop
Senior Member
Join Date: Aug 2014
Old 07-01-2018 , 12:47   Re: (fake) Classes/Objects in SourcePawn
Reply With Quote #5

Quote:
Originally Posted by hmmmmm View Post
CustomKeyValues

[...] The main aim was to get data from maps/mappers that they can implement as KeyValues from hammer, but you can also set keys/values from the plugin side.
Oh right, that's a thing! Didn't think about being able to dispatch keys through plugins myself.

It doesn't seem like any of the nested StringMaps in your plugin get disposed until the next OnLevelInit call, so if I dispatch keys to a lot of short-lived entities on a long map, it'd be a bit leaky.

I had a proof-of-concept for something similar (minus native KV dispatch) as the groundwork for a cleaner Custom Weapons-like plugin framework; never got around to finishing the API design though.

But anyways, to get back on the topic of fake objects: definitely think about whether your use-case needs completely custom object-oriented programming logic and storage; don't do OOP for the sake of it.
__________________
I do TF2, TF2 servers, and TF2 plugins.
AlliedModders Releases / Github / TF2 Server / Donate (BTC / BCH)
nosoop is offline
Headline
SourceMod Moderator
Join Date: Mar 2015
Old 07-01-2018 , 18:58   Re: (fake) Classes/Objects in SourcePawn
Reply With Quote #6

Quote:
Originally Posted by nosoop View Post
StringMaps are great for temporary mappings that should last as long as the plugin, but the serialization is very much DIY.
If serialization is necessary then switching to a KeyValues-based methodmap is okay, but I'd rather write a conversion method from a StringMap to KeyValues and eat that performance cost then, when serialization is used, rather than on every call into the KeyValues structure.

Either way works, but that's my two cents
Headline 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 17:05.


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