[Tutorial] Optimizaciones (Tips & Tricks)
#1

Optimizaciones (Tips & Tricks)

Introducciуn:
A lo largo de mi experiencia ayudando en tуpicos y otros, en varias ocasiones he visto cуmo las personas cometen varias malas prбcticas al hacer un cуdigo.
En este tutorial voy a enseсar varios consejos y trucos, voy a mostrar que la lуgica se aplica al momento de optimizar nuestro cуdigo, las varias formas que existen de hacer un mismo cуdigo y cуmo encontrar la mejor. Tomarй como muestra varios gamemodes y filterscripts que tengo descargado en mi PC.

Recuerden que йsto se perfecciona con el tiempo, solo es cuestiуn de llevarlo a la prбctica.


їCуmo comienzo a hacer un cуdigo?
Se van a preguntar quй tiene que ver йsto con el tutorial. Pues querнa aсadirlo como para empezar.

їCуmo comienzo a hacer un cуdigo? Lo primero que tenemos que tener en mente es la base de nuestro cуdigo (con esto no me refiero a lo que queremos hacer, sino de cуmo queremos que se haga).
Primeramente hagan su cуdigo sin preocuparse en la optimizaciуn ni la velocidad, solamente preocupensen en que el cуdigo haga lo que ustedes quieren que haga y sea funcional.
Luego cuando crean que ya lo tiene listo, re-comiencen a escribirlo y ahн sн fнjensen en cуmo lo pueden hacer de la mejor forma. Porque si nos preocupamos por 2 cosas a la vez, que sea optimizado y funcional, tal vez podrнamos no cumplir con lo principal que es que funcione y nos desanimarнamos.
Hagan esto las veces que sea posible (escribir, optimizar, re-escribir, optimizar, y asн...)

Hagan sus pruebas de velocidad e intenten escribiendo el cуdigo de otra forma, para asн estar seguro de cuбl es la mejor opciуn por optar.

Esta prбctica en lo personal siempre me funcionу. Una vez tuve que re-comenzar a escribir un GM DESDE 0, tomando como base el anterior y asн hacerlo de una mejor forma.


їCуmo aplicamos la lуgica?
A veces cometemos el error de crear varias variables para identificar tan solamente una cosa.
Por ejemplo, tenemos 2 variables, "IsSpectating" y "SpecID" que ya sabemos para quй se utilizan. Pero en realidad solo necesitamos 1 variable para saber si el jugador estб espectando o no, y esa variable es "SpecID".
Y si por ejemplo, queremos saber si el jugador estб en modo espectador pero no estб espectando a nadie? Tendrнa que verificar si "IsSpectating" es 1 y "SpecID" es INVALID_PLAYER_ID, pero hay una forma de seguir haciйndolo solo con "SpecID":

En OnPlayerConnect ponemos que "SpecID" sea -1, ya que si es 0 corresponderнa a una ID vбlida. Si pones al jugador en modo espectador, esa variable cambiarнa a MAX_PLAYERS, ya que esa ID corresponderнa a una ID invбlida. Y cuando ponemos a un jugador a espectar a otro, ahн sн "SpecID" tendrнa que tener la ID del jugador a espectar. Entonces:

- Verificamos si el jugador no estб espectando cuando "SpecID" es -1.
- Verificamos si el jugador estб en modo espectador pero espectando a nadie cuando "SpecID" es MAX_PLAYERS.
- Un jugador estб espectando cuando su valor corresponde a una ID vбlida.

Y que hacemos con GetPlayerState, que devuelve 9 cuando un jugador estб espectando? Pues lo podrнamos usar como anti-cheat:

pawn Код:
if(GetPlayerState(playerid) == PLAYER_STATE_SPECTATING && pInfo[playerid][SpecID] == -1)
{
    // Tu cуdigo
}

Otro ejemplo que es muy comъn en muchos GMs. Muchos servidores tienen las tнpicas 2 variables que identifican si el jugador estб registrado y si estб identificado (logueado, como se dirнa vulgarmente), pero realmente es necesaria la de registro?
Veamos, si un jugador estб identificado, estб lуgicamente registrado. Y cуmo identificamos si estб registrado? Simplemente chequeamos si existe una cuenta con su nombre.

Y asн podrнa seguir con varios ejemplos mбs, pero el punto es: para quй crear otras variables si ya tenemos 1 que puede cumplir fбcilmente con las demбs?

Mбs ejemplos? Йstos son los que vi en el famoso Ladmin de LethaL:

* "Muted" & "MutedTime": para quй necesitamos "Muted"? Si "MutedTime" es mayor a 0 si un jugador estб silenciado.
* "Spawned" & "TimesSpawned": "Spawned" verifica si el jugador ya ha spawneado, por lo menos 1 vez. "TimesSpawend" -que almacena las veces que un jugador "spawneo"- tambiйn lo puede hacer.
* "DoorsLocked": comprueba si el jugador bloqueу su vehнculo. Actualmente existe una funciуn que hace йso, verificar si el vehнculo estб bloqueado: https://sampwiki.blast.hk/wiki/GetVehicleParamsEx.



Variables innecesarias
Siempre tuve la obsesiуn de reducir al mнnimo el uso de esas variables globales que, la mayorнa del tiempo estбn en la memoria haciendo nada mбs que ocupar un espacio.
Por ejemplo, yo tenнa un PTD (Player-TextDraw) que mostraba cierta informaciуn del jugador cuando este se identificaba, luego de йso el PTD se ocultaba y solo ocupaba un espacio en la memoria.
Lo que bбsicamente hice fue, hacer que el PTD se cree en el momento en el que el jugador se identificaba, y luego destruirlo cuando tenнa que ocultarlo (aсadiendo la ID del PTD en los parбmetros de SetTimerEx).
Sй que es estъpido y algo obvio, pero crйanme que he visto йste tipo de problema en varias oportunidades.

Otro caso es crear una variable que cuente la cantidad de advertencias que obtiene un jugador al escribir mal su contraseсa, y luego de йso la variable no se usarб mбs, quй se puede hacer? Pues bбsicamente utilizar un PVars que almacene las advertencias, luego cuando el jugador ingrese o sea expulsado, eliminar ese PVar.

Los PVars pueden ser usados cuando sabemos que no serбn llamados muy a menudo en nuestro script. Por ejemplo, cuando queremos restringir un comando por un tiempo determinado, de quй sirve crear una variable global y usarla solamente cuando ese comando es llamado?

Tambiйn cuando sabemos que un jugador tal vez podrнa no usar esa variable, por ejemplo cuando almacenamos una posiciуn (con el comando /saveplace) para un jugador VIP, o sea no todos los jugadores conectados en nuestro servidor son VIPs por lo que esas variables hasta quizбs no serбn utilizados.



Mismo objetivo, varias formas
Como dije, hay varias formas de lograr un objetivo, pero solo 1 es la mejor.
Siempre todo es mбs rбpido si usamos variables como "cachй" o memoria intermedia que guarda un valor -que en otro caso deberнamos encontrarlo con un cуdigo auxiliar- pero a veces podrнa producirte un consumo de memoria algo significativo.

Por ejemplo, quiero saber quй ID de jugador estб manejando X vehнculo. Tengo 2 opciones.

Opciуn 1: crear una variable para cada vehнculo (que por defecto es 2000) que guarde la ID del jugador que lo estб manejando (lo escribo lo mбs optimizado posible - teniendo en cuenta que en mi servidor no habrб mбs de 255 slots).
pawn Код:
static Vehicle_DriverID[MAX_VEHICLES char];

public OnPlayerStateChange(playerid, newstate, oldstate)
{
    if(newstate == PLAYER_STATE_DRIVER) Vehicle_DriverID{GetPlayerVehicleID(playerid)} = playerid;
    return 1;
}

stock GetVehicleDriverID(vehicleid) return Vehicle_DriverID{vehicleid};

Opciуn 2: crear una funciуn que retorne la ID de jugador que estб manejando X vehнculo.
pawn Код:
stock GetVehicleDriverID(vehicleid)
{
    for(new i = 0; i < MAX_PLAYERS; i++) // En otros casos, utilizar foreach
    {
        if(GetPlayerVehicleID(i) != vehicleid) continue;
        return i;
    }  
    return -1; // Retornar una ID invбlida
}

En la primera opciуn -que es mбs rбpida, ya que obtenemos nuestro valor de forma directa- estarнamos arriesgando memoria por velocidad, mientras que en la segunda opciуn -que es mбs lenta, ya que buscamos en cada jugador si estб manejando el vehнculo dicho- arriesgamos velocidad por memoria.
Esto queda siempre a tu criterio, tomando en cuenta de cuбnta memoria consume tu servidor.



Algunos Tips
Como para ir terminando quiero agregar algunos consejos bбsicos y enlaces:
  • Tips:
    • Cambiar el valor de MAX_PLAYERS a la cantidad de slots que usas.
    • Cambiar el valor de MAX_VEHICLES a la cantidad de vehнculos que usarнas -haciendo una suposiciуn-
    • Fнjate bien cuбn largo puede ser una array. No utilices mбs memoria de la que podrнas llegar a usar.
    • Si tienes un array que solo contendrб valores que estбn en la tabla ASCII, divide ese array por 4 y manipula los valores por byte, y no por celda (como tus variables tipo booleanas, utilizando este tag -bool:- no harб que tu variable consuma menos memoria).
    • Cуmo dejar "en blanco" un array? De esta forma: my_array = "";
    • Si utilizas LAdmin como sistema administrativo, cбmbialo! Hay miles de sistemas y mбs sofisticados. Ademбs, LAdmin tiene muchos problemas de rendimiento.
    • Por continuar...

Acб dejo una citaciуn de un comentario de ****** que es muy interesante:
Quote:
Originally Posted by ******
Посмотреть сообщение
There are MUCH better ways to optimise your code, which I think I should return just to write a tutorial on, as this unhealthy obsession with non-optimisations is largely my fault, and I am eternally sorry for that! I still have to rectify this mistake.

There are five steps to optimising your code:
  • Profile it to find the slow parts.
  • Stop there because you probably don't need to go any further.
  • Profile again because profiling.
  • Use a better algorithm, not a comma instead of a semi-colon.
  • Profile again to check that the change you made actually improved things.
Algorithms are the way to go. The worst coded, primitive, and ugly quicksort function will destroy a bubblesort function written using every combination of micro-optimisation imaginable. Heck, for any decent array size a naive quicksort implementation in simple PAWN will destroy a bubblesort implementation even in hand-tuned x86 assembly. THAT is the power of better algorithms.

Algunos enlaces que te podrнan ayudar:
Tiny But Super Optimizations - Crayder
Fastest String Loop - SickAttack
Tips & Tricks - Slice
New Code Optimizations - Yashas
Creative & smart scripting ideas - improve performance & readability at the same time - Yashas
Command Processor [Faster Than I-ZCMD!] - SickAttack
foreach 0.4.1 standalone include - ****** (re-subido por Kar).
file_system - Fбcil lector de datos - EnzoMetlc (descubrн que escribe/lee datos mбs rбpido que incluso y_ini, pero aъn espero una confirmaciуn de ******).

Recuerden que por mбs optimizaciones que le demos, SA-MP procesa los cуdigos muy rбpidamente (tanto que algunas veces hay que ejecutar el mismo cуdigo unas miles de veces para notar una diferencia de tiempo). Pero siempre serб preferible mantener un servidor rбpido por el bien del mismo.


Si tenes algъn consejo o truco, comйntalo! Si hay algъn error dнmelo y lo arreglarй
Espero que les sirva este tutorial, saludos!
Reply


Messages In This Thread
Optimizaciones (Tips & Tricks) - by Swedky - 18.11.2016, 03:56
Respuesta: Optimizaciones (Tips & Tricks) - by OTACON - 18.11.2016, 05:30
Respuesta: Optimizaciones (Tips & Tricks) - by Juance - 18.11.2016, 14:07
Respuesta: Optimizaciones (Tips & Tricks) - by Gles - 18.11.2016, 17:54
Respuesta: Optimizaciones (Tips & Tricks) - by Swedky - 20.11.2016, 18:54
Respuesta: Optimizaciones (Tips & Tricks) - by StrakerHD - 20.11.2016, 20:25
Respuesta: Optimizaciones (Tips & Tricks) - by Goncho28 - 20.11.2016, 20:47
Respuesta: Optimizaciones (Tips & Tricks) - by BrianFaria - 22.11.2016, 07:56

Forum Jump:


Users browsing this thread: 1 Guest(s)