AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Snippets and Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=112)
-   -   Classes/Objects in SourcePawn (https://forums.alliedmods.net/showthread.php?t=308487)

headline 06-22-2018 00:01

Classes/Objects in SourcePawn
 
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.

http://i.michaelwflaherty.com/TT5wv.png

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.

ddhoward 06-30-2018 00:08

Re: (fake) Classes/Objects in SourcePawn
 
Quote:

Originally Posted by Neuro Toxin (Post 2599992)
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.

nosoop 06-30-2018 22:51

Re: (fake) Classes/Objects in SourcePawn
 
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.

hmmmmm 07-01-2018 03:30

Re: (fake) Classes/Objects in SourcePawn
 
Quote:

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

CustomKeyValues :D

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.

nosoop 07-01-2018 12:47

Re: (fake) Classes/Objects in SourcePawn
 
Quote:

Originally Posted by hmmmmm (Post 2600247)
CustomKeyValues :D

[...] 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.

headline 07-01-2018 18:58

Re: (fake) Classes/Objects in SourcePawn
 
Quote:

Originally Posted by nosoop (Post 2600231)
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


All times are GMT -4. The time now is 12:47.

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