This site is a testing version, but all data is shared with the live forum.


Raised This Month: $ Target: $400
 0% 

[TUT/INFO] set_tasks: when they are and when they aren't necessary


  
 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
Author Message
Hawk552
AMX Mod X Moderator
Join Date: Aug 2005
Old 08-12-2006 , 12:34   [TUT/INFO] set_tasks: when they are and when they aren't necessary
Reply With Quote #1

This tutorial is intended for beginner-intermediate level scripters.

set_task can sometimes be an extremely useful function, but other times it is really overkill. What few people know is that it is a very expensive operation, the CPU has to literally check every cycle if it is time for the set_task to be executed. Usually, there are ways around a set_task.

set_task also has the restriction of being unable to be called more than every 0.1 seconds. This means that if you pass 0.01 in parameter 1, it will be clamped at 0.1.

But what can we do to avoid it? Sometimes you really have to use a set_task, such as here:

Code:
#include <amxmodx> #include <amxmisc> #include <engine> public plugin_init() {     register_plugin("ROFL","1.0","Hawk552")         register_event("ResetHUD","EventResetHUD","be") } public EventResetHUD(id)     set_task(1.0,"DelayedResetHUD",id)     public DelayedResetHUD(id)     DispatchSpawn(id)

But why? There is no real way to escape delaying the function once without doing something more CPU intensive or unreliable. We could create an ent and make it think in 1 second (which will be covered later), but that not only adds an unnecissary spawn for such a small thing, it also is more unreliable (i.e. the server could crash due to too many ents, or it could be failed to be spawned and the function simply has to end there).

But there are other times where escaping a set_task is not only easier, but less resource consuming.

One of the commonly known ways of doing this is the forward client_PreThink / FM_PlayerPreThink. This forward is called every frame on a client before rendering physics. In this forward, you would do things that generally must be constantly updated, like velocity or changing rendering.

Here is an example:

Code:
#include <amxmodx> #include <amxmisc> #include <engine> public plugin_init()     register_plugin("ROFL","1.0","Hawk552") public client_PreThink(id) {     static Float:Velocity[3]     entity_get_vector(id,EV_VEC_velocity,Velocity)         Velocity[2] = -floatabs(Velocity[2])         entity_set_vector(id,EV_VEC_velocity,Velocity) }

Why is a set_task unsuitable here? For two reasons: 1) the half-life engine will allow you to have timers anyway (to a varying degree), and 2) it will look very glitchy since if the client has 60 FPS, the server is only checking every 10 frames if their velocity is what it should be.

One of the less practiced ways of avoiding set_tasks is to spawn an entity, set its nextthink to whatever you want, and register_think/FM_Think it. But when is this necessary? Pretty much whenever you use the "b" flag in set_task, it's better to use this method. It's also preferred when you have already spawned an entity (such as an NPC) and want to make it say, disappear, in x seconds.

Here is an example:

Engine:
Code:
#include <amxmodx> #include <amxmisc> #include <engine> new g_Classname[] = "roflmao" public plugin_init() {     register_plugin("ROFL","1.0","Hawk552")         new Ent = create_entity("info_target")     entity_set_string(Ent,EV_SZ_classname,g_Classname)     entity_set_float(Ent,EV_FL_nextthink,20.0)         register_think(g_Classname,"RoflmaoThink") } public RoflmaoThink(Ent) {     log_amx("ROFLMAO thinks.")         entity_set_float(Ent,EV_FL_nextthink,20.0) }

Fakemeta:
Code:
#include <amxmodx> #include <amxmisc> #include <fakemeta> new g_Classname[] = "roflmao" public plugin_init() {     register_plugin("ROFL","1.0","Hawk552")         new Ent = engfunc(EngFunc_CreateNamedEntity,engfunc(EngFunc_AllocString,"info_target"))     set_pev(Ent,pev_classname,g_Classname)     set_pev(Ent,pev_nextthink,20.0)         register_forward(FM_Think,"ForwardThink") } public ForwardThink(Ent) {     static Classname[33]     pev(Ent,pev_classname,Classname,32)         if(!equal(Classname,g_Classname))         return FMRES_IGNORED         log_amx("ROFLMAO thinks.")         set_pev(Ent,pev_nextthink,20.0)         return FMRES_IGNORED }

This is useful, as said, for escaping the usage of flag "b" on set_task, or executing set_task at the end of the function called.

The final way to escape a set_task is when using cooldowns. For example, you want a player to be able to use a special attack every 30 seconds.

Code:
#include <amxmodx> #include <amxmisc> #include <fakemeta> // this is how often you want your players to be able to use your attack #define ATTACK_COOLDOWN 20.0 new Float:g_LastAttack[33] // optimization new Float:g_Cooldown = ATTACK_COOLDOWN public plugin_init() {     register_plugin("ROFL","1.0","Hawk552")         register_clcmd("myattack","CmdMyAttack") } public CmdMyAttack(id) {     // to use engine instead, use this:     /* new Float:Time = halflife_time() */     new Float:Time     global_get(glb_time,Time)             if(!is_user_alive(id) || Time - g_Cooldown < g_LastAttack[id])         return         g_LastAttack[id] = Time         // your code here }

I'm not going to push this any longer, so if you have any questions about it then feel free to ask.
__________________
Hawk552 is offline
Send a message via AIM to Hawk552
 



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 13:35.


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