AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Snippets and Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=112)
-   -   [TUT] SourcePawn Scripting - Tips, Basics to Advanced (https://forums.alliedmods.net/showthread.php?t=321089)

Dragokas 12-03-2020 13:59

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Addition for "3. Connect to Server" section.

Recently, they updated something in security, and a method for running client via left4dead2.exe (with arguments) in the same machine with a server is no more working.

Instead, here is a walkaround to run the app directly from steam.exe.
I'm attaching the full code of .bat script (to run server + join simultaneously):

Spoiler


For other games, change appID 550 by your game's Id from steam.inf file, and GAME_ALIAS value with an appropriate game name alias.

Dragokas 01-10-2021 14:38

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Published Russian translation of the article, with some additions:

Spoiler

Uncle Jessie 04-04-2021 04:52

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Something like this is useful too
Using this script instead of the random start map plugins

Spoiler

Dragokas 04-09-2021 08:43

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Half-Life Position, Velocity, and Angles (for n00bs)

Mystik Spiral 07-05-2021 16:11

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
On the first page, in section...

...and subheading...

Code:

SourcePawn specific editors
...please consider adding a link for...

Code:

SPCode - fork of SPEdit which aims to fix issues and add some small features

Silvers 07-06-2021 05:05

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Done. Thanks.

little_froy 08-19-2021 09:44

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
strcmp() provides less readable and worse compatibility compared to StrContains()

MAGNAT2645 08-19-2021 14:17

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
You can also mention the "stringize" operator (inherited from Pawn) which converts arguments to packed strings in a macro.
I don't find it that useful but still here's an example:
Code:

// Note that spaces inside parentheses count too!!! STRINGIZE( abc123 ) = " abc123 "
#define STRINGIZE(%0) #%0

ConVar myplugin_enabled; // typical toggle convar

Action ServerCmd_DoStuff(int args) {
        if ( !myplugin_enabled.BoolValue ) {
                PrintToServer( "Plugin is disabled! " ... STRINGIZE(myplugin_enabled) ... " = 0" ); // "Plugin is disabled! myplugin_enabled = 0"
                return Plugin_Handled;
        }

        // ...

        return Plugin_Handled;
}


Dragokas 08-20-2021 10:00

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by little_froy (Post 2755614)
strcmp() provides less readable and worse compatibility compared to StrContains()

What kind of compatibility are you talking about?
These functions have different meanings.

MAGNAT2645, interesting ability, but IMHO, useless sample =) Can't find where it could be useful. The same can be written by manual string enquoting.

Psyk0tik 08-20-2021 10:38

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by little_froy (Post 2755614)
strcmp() provides less readable and worse compatibility compared to StrContains()

Judging by the context of how "strcmp" is referenced in the main post, I would assume that you think "StrContains" is more "readable" and has better "compatibility" when it comes to comparing two strings, which is completely false and irrelevant to the purpose of "strcmp"/"StrEqual". The "StrContains" function checks if a string contains a substring, whereas "strcmp"/"StrEqual" compares two strings to determine if they are equal. Just because a string may contain a substring that starts at index 0, doesn't mean that the string is equal to the substring.

MAGNAT2645 08-20-2021 19:00

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by Dragokas (Post 2755713)
MAGNAT2645, interesting ability, but IMHO, useless sample =) Can't find where it could be useful. The same can be written by manual string enquoting.

As i said, it's not that useful. You can use it in a macro to join text (and put it without quotes).
Code:

#define ERROR(%0) PrintToServer( "ERROR: " ... #%0 )

int a = 5;
int b = 0;
int c;
if ( b == 0 ) ERROR(Division by zero!);
else          c = a / b;

But, it's better to use quotes for better readability
Code:

#define ERROR(%0) PrintToServer( "ERROR: " ... %0 )
if ( b == 0 ) ERROR( "Division by zero!" );


zomexf 09-20-2021 13:12

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Use OnClientPostAdminCheck or OnClientPutInServer : SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);

Whether it is necessary to use "SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage)" in OnClientDisconnect;

I want to know.

Psyk0tik 09-20-2021 13:20

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by zomexf (Post 2758318)
Use OnClientPostAdminCheck or OnClientPutInServer : SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);

Whether it is necessary to use "SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage)" in OnClientDisconnect;

I want to know.

Hook inside OnClientPutInServer since that's when players join the server. I would only hook inside OnClientPostAdminCheck if you plan on checking admin flags to determine if they should be hooked.

Entities are automatically unhooked by SDKHooks when they leave (if they are player entities) or are deleted.

Silvers 09-20-2021 13:38

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Using OnClientPostAdminCheck is bad for anything other than when checking for admin flags, since if Steam goes offline they are not verified and the forward will not trigger.

zomexf 09-20-2021 14:48

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Thanks. :)

NoroHime 03-15-2022 06:24

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
I'm some confuses using entity reference, when I check for validate entities before using each entity does that mean I don't need entity references?

Silvers 03-15-2022 07:08

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by NoroHime (Post 2774235)
I'm some confuses using entity reference, when I check for validate entities before using each entity does that mean I don't need entity references?

I'll make it clearer in the post.

You want to use entity references and userid's for anything asynchronous such as CreateTimer, RequestFrame or when you're storing an entity index in an array. Anything that will be accessed later and not immediately in the same frame/functions where you have the entity index.

NoroHime 03-15-2022 07:58

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by Silvers (Post 2774237)
I'll make it clearer in the post.

You want to use entity references and userid's for anything asynchronous such as CreateTimer, RequestFrame or when you're storing an entity index in an array. Anything that will be accessed later and not immediately in the same frame/functions where you have the entity index.

yeah, for this point wiki is explain clearly
but my confuses is what merit to use entity references? does OnEntityDestoyed cant handle all of the entity status change situations? or ent ref just double check here
or conversely, if enf ref check passed, that mean we dont have to use IsValidEntity or IsValidEdict
a digression, under which scene we should use Edict operation rather than Entity Operation?
very thanks silvers patiently anser
----
for the edict i found from main thread, sorry im reading slowly

Marttt 03-16-2022 06:36

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Follow this events order as example:

OnEntityCreated -> PostSpawn -> RequestFrame -> CreateTimer(timerReadEnt) -> EntityDestroyed > timerReadEnt

in timerReadEnt you will get an exception if you use the entity index cause it's gone (or replaced by another entity with the same index).

Storing the entity as EntRef allow you to post-check if that entityRef has an INVALID_REFERENCE (with EntRefToEntIndex) before using it.

The logic is the same as what happens to the player. (GetClientUserId)

Dragokas 03-16-2022 08:50

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by NoroHime (Post 2774242)
but my confuses is what merit to use entity references?

NoroHime, the merit of using entity ref -> they are much more unique (higher range of values, like == index + time). There is a high chance the entity with index e.g. 123 will be destroyed and the new entity will be created with the same 123 index during asynhronous operation. The the next time when you chech this entity and expect it to be the same as it was at creation time, that will not be true: IsValidEntity will return true, but the entity is replaced.

Quote:

Originally Posted by NoroHime (Post 2774242)
does OnEntityDestoyed cant handle all of the entity status change situations?

You could use OnEntityDestoyed with your entities array. However, usually a single IsValidEntity operation is more efficient.

Quote:

Originally Posted by NoroHime (Post 2774242)
... or conversely, if enf ref check passed, that mean we dont have to use IsValidEntity or IsValidEdict

Well, personally I always check validity after dereference, like so:
PHP Code:

int soul EntRefToEntIndex(g_iGlowRef[client]);
        
if (
soul && soul != INVALID_ENT_REFERENCE && IsValidEntity(soul)) 

I think it's required. However, you can try remove entity and experiment with dereference on your own to see if error persist.

Silvers 03-16-2022 14:22

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by Dragokas (Post 2774339)
I think it's required. However, you can try remove entity and experiment with dereference on your own to see if error persist.

I would have thought deref would be enough but I recall having one or two reports of invalid entities after deref so it seems to be required, very rare cases nonetheless.

NoroHime 03-16-2022 23:29

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
thanks everyone patiently anser, i got point that unique is important,
although it is a bit unsightly code to use, but i tend to use like this
PHP Code:

timer(int entref){
    
int ent;
    if (
ent UnpackEnt(entref)) {
    
/*operation*/
    
}
}

int UnpackEnt(int entref) {
    
int unpacked EntRefToEntIndex(entref);
    if (
unpacked != INVALID_ENT_REFERENCE && IsValidEdict(unpacked))
        return 
unpacked;



AdRiAnIlloO 03-21-2022 12:04

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
I recently realized cleaning entity index trackers was also an option (from OnEntityDestroyed) and lately used that approach instead of entity references system, for just one entity as max. in my case. However, cleaning the appropiate variable can become inconvenient once handling enough amount of possible tracked entities, as it requires conditioning to match against the appropiate variable each case.

But as long as you handle few entity tracking variables, storing indices is perfectly adequate and efficient in terms of a gameplay session (vs. calling EntRefToEntIndex continuatedly) as long as you clear the variables at OnEntityDestroyed (aka assigning them to e.g. INVALID_ENT_REFERENCE).

Obviously this approach is unproductive if perfoming extra checks other than entity != INVALID_ENT_REFERENCE for validating.

Dragokas 03-21-2022 12:36

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
AdRiAnIlloO, same mistake as I described above. Those entity can be replaced very soon. So, your kind of check will return "entity exists and valid", however, that is other entity, not the one you initially tracked. As a result you will target (and perhaps, further delete) someone else's entity, causing hard-to-trace bug. EntIndexToEntRef guarantee the index become unique and will not be replaced with another one newly created entity having same ref index.

AdRiAnIlloO 03-23-2022 04:03

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Citing your own quote.

Quote:

Originally Posted by Dragokas (Post 2774339)
You could use OnEntityDestoyed with your entities array. However, usually a single IsValidEntity operation is more efficient.

This is what I exactly suggested, expanding the reasoning with how to ensure it overcomes EntRefToEntIndex approach (basically not calling that nor IsValidEntity, etc.) as one already has the tracked value set/cleaned to e.g. INVALID_ENTITY_REFERENCE at OnEntityDestroyed.

Or, is it that OnEntityDestroyed could be called after engine assigned the passed index to a new entity? From the SDK, entities are usually totally removed one frame after requested, for security reasons, during which I wonder if engine could free their index (haven't reached to confirm it).

But basically what he is saying is the same than you and me pointed, why not to use the OnEntityDestroyed approach when it seems perfectly valid (if not loosing productivity, as I explained) against ent ref checks.

Dragokas 03-23-2022 09:36

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Well, I already explained. But, ok, show me code example of a real task according to your suggestion and I'll tell you why.

AdRiAnIlloO 03-26-2022 07:54

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Sorry for the delay, was busy. Here goes the parts of interest for my entity-tracking variable (which aims to refer to an env_sprite):

Code:

int gKingSprite = INVALID_ENT_REFERENCE; // Global scope declaration

public void OnEntityDestroyed(int entity)
{
        if (entity == gKingSprite)
        {
                gKingSprite = INVALID_ENT_REFERENCE; // The "cleaning"
        }
}

void AwardKingSprite() // One of the functions of entity validating interest (called at times from my specific needs)
{
        if (gKingSprite == INVALID_ENT_REFERENCE) // Safe cheap checking thanks to the OnEntityDestroyed cleaning
        {
                if ((gKingSprite = CreateEntityByName("env_sprite")) == INVALID_ENT_REFERENCE)
                {
                        return;
                }

                // <Entity setup code>...
        }
}

As you can see, this is a clear example of the previous reasonings. In case the entity gets deleted, the variable should go INVALID_ENT_REFERENCE, eliminating the need to perform expensiver checks (EntRefToEntIndex, IsValidEntity...) other than '==' (or '!=' depending on the concrete direction of interest) at the highlighted line of the code fragment.

Note SM should always pass entity indices for networked (edict-full) entities (and internal entrefs for non-networked entities instead) to the entity forwards.

PS: Also, I've confirmed OnEntityDestroyed only gets called upon total entity destruction (that is, after the security game frame happens originated from the common entity destroy requests from Source games): CGlobalEntityList::NotifyRemoveEntity -> SDKHooks::OnEntityDeleted, but it seems the edict (and thus, index) should be destroyed right after.

Dragokas 03-26-2022 08:21

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Yeah, in such way it is safe.
I don't remember which one case I told above, sorry.

Silvers 03-26-2022 09:21

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by AdRiAnIlloO (Post 2775245)
eliminating the need to perform expensiver checks (EntRefToEntIndex, IsValidEntity...) other than '==' (or '!=' depending on the concrete direction of interest) at the highlighted line of the code fragment.

If the entity is not being accessed very often then this may end up using more CPU cycles than EntRefToEntIndex and check. They are not expensive at all, so that statement of yours is wrong.

plug344 03-28-2022 05:05

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Which is faster, FormatEx or strcopy?

Dragokas 03-28-2022 09:19

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
strcopy has less logic, should be faster.
Also, if you need stringbuilder functionality, use strCat; it doesn't re-create string buffer unlike Format.

plug344 03-29-2022 04:41

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Thank you very much,

the various "handle.method" of the new syntax seems to be just the wrapper of the old syntax, is there a difference in their speed? Such as "ClearArray (ArrayList)" and "ArrayList.Clear()", etc.

Psyk0tik 03-29-2022 07:21

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
You can use either-or. The speed is irrelevant. It’s more a matter of preference rather than which one is slightly faster.

If you’re really curious about it, you can use the profiler. Pre-optimizing your plugin is a waste of time. Unless you’re actually experiencing performance issues with your plugin, don’t worry so much about choosing the fastest method/function for every part of your code. You may end up sacrificing readability, maintainability, and simplicity for a negligible difference in speed.

Optimizing Plugins (SourceMod Scripting)

Silvers 03-29-2022 10:47

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
For something like this optimizing is negligible but I wouldn't advise against optimizing especially if the plugin will be made publicly available. Many public ones have huge performance hits due to bad practices and some servers running many plugins will feel the degradation in performance due to certain unoptimized plugins.

iaNanaNana 04-13-2022 03:50

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
I have a question: int i[N][33] or ArrayList i[33] Which is better? The before cause too many plugin file size after compiled

Marttt 04-13-2022 15:00

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
"Which is better" most of the time depends on the situation and the use case.
You should share an example and mention the "before" and "after" sizes as well.

iaNanaNana 04-15-2022 09:03

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Quote:

Originally Posted by Marttt (Post 2776700)
"Which is better" most of the time depends on the situation and the use case.
You should share an example and mention the "before" and "after" sizes as well.

PHP Code:

int iConfig[100][MAXPLAYERS]

public 
OnClientPutInServer(a)
{
    
iConfig[0][a] = 1
}

public 
OnClientDisconnect(a)
{
    
iConfig[0][a] = 0


or
PHP Code:

ArrayList hConfig[MAXPLAYERS]

public 
OnClientPutInServer(a)
{
    
ArrayList hConfig[a] = new ArrayList(1,100)
    
hConfig[a].Set(01)
}

public 
OnClientDisconnect(a)
{
    
delete hConfig[a]


I wanna use to store clients configures when in game, reset values or delete ArrayList when disconenct.

Silvers 04-15-2022 09:30

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
Should be: MAXPLAYERS+1 not just MAXPLAYERS

Dragokas 04-15-2022 11:13

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
iaNanaNana, you don't need array of lists, it is already an "array" of blocks.
Also, alloc/release handles is a heavy operation.
See:
PHP Code:

ArrayList     hConfig;

public 
void OnPluginStart()
{
    
hConfig = new ArrayList(ByteCountToCells(4), MAXPLAYERS+1); // 4 bytes (int or float)
    
    // or
    // hConfig = new ArrayList(ByteCountToCells(4));
    // hConfig.Resize(MAXPLAYERS+1);
}

public 
void OnClientPutInServer(int client)
{
    
hConfig.Set(client10); // write 1 at block 0
}

public 
void OnClientDisconnect(int client)
{
    
hConfig.Set(client00); // write 0 at block 0


or write multiple values, e.g. int + float using different arraylist's blocks:
PHP Code:

ArrayList    hList;

public 
void OnPluginStart()
{
    
hList = new ArrayList(ByteCountToCells(8)); // 8 bytes (int + float)
}

public 
Action SomeCommand(int clientint argc)
{
    
int countattacker;
    
float hpfPercent[MAXPLAYERS+1] = ......
    
    for( 
int i 1<= MaxClientsi++ )
    {
        if( 
SomeCondition )
        {
            
hList.Resize(count 1);
            
hList.Set(cntfPercent[i], 0);     // block 0 - float (e.g. % HP)
            
hList.Set(cnti1);                // block 1 - int (client index)
            
++ count;
        }
    }

    
hList.Sort(Sort_DescendingSort_Float);
    
    for( 
int i 0hList.Lengthi++ )
    {
        
attacker al.Get(i1); // read block 1
        
hp al.Get(i0);         // read block 0
    
}
    
// ...


But, for simple tasks the simple arrays is much more faster.

sorallll 04-16-2022 00:21

Re: [TUT] SourcePawn Scripting - Tips, Basics to Advanced
 
I would like to ask, how to calculate the number of bytes occupied by the string in IntToString, FloatToString


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

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