Metodos de estructuración de codigo
#1
Nota: Sigue en edición, lo publique por error, di un click infalso y lo publique.. pls

Esto más que nada son algunos de mis consejos (en mi opinión) de como estructurar un código para una buena interpretación de este a la hora de compilarlo, pues como sabemos, Pawn es un lenguaje estructurado y al saber como manejar correctamente su flujo de datos, nos podemos ahorrar unos cuantos megas de memoria y unos dolores de cabeza, la estructura de tu código debe tener una manera en el que el código sea leído de una manera rápida y eficiente, considerando todos los métodos de optimización que hayas aprendido hasta ahora y todos los conocimientos que tienes, digamos que es necesario un nivel medio-avanzado de programación para llevar a cabo estos temas.



1. Flujo de datos atravez de condiciones.

Lo más importante en los lenguajes de programación es controlar el flujo de los datos atravez de las sentencias if, estas son muy importantes en su forma de interpretar el código, pero hasta donde sabemos, hacer condiciones sin sentido lo único que crea es que el procesador tarde más en leer la cadena de sentencias y comparar todos sus resultados para ver si debe tomar la ruta de esta sentencia.



Un ejemplo sería:

Código PHP:
// ESTO ESTA MAL [X]

    // Porque? estas chequeando si esta vivo en una función que solo puede ser llamada cuando

    // el jugador esta vivo, el procesador tarda mas tiempo en leer la sentencia cuando esta usualmente

    // siempre dara true (puede dar false en algunos casos) sin mencionar que debajo de las nativas

    // tambien se esconde un codigo que dependiendo del costo de la operación, puede tener resultados fatales.

    
if(is_user_alive(id) && !(pev(idpev_flags) & FL_ONGROUND) && g_someglobalvariablepls[id])

        
// Algun codigo muuuuy muuuuy largo..

    

    // Otro codigo un poco menos largo que el de arriba..


Esto facilmente se puede arreglar preguntando y/o leyendo el SDK para ver que chequeos y que otras cosas hace una función a la hora de programar tu estructura, para así evitar poner sentencias inutiles.

Otra cosa que tambien puede ser un dolor de cabeza, es la mala estructuración de los anclajes en sentencia, lo que provoca que pueda tirar falsos positivos/negativos.



Ejemplo:

Código PHP:
new g_randomvar[3]

        
g_randomvar[0] = 6

        g_randomvar
[1] = 26

        g_randomvar
[2] = -1



public fw_AlgunaFuncion(identFloat:magnitud[3])

{

    
// Esta función segun nosotros es esta logica.

    // Si g_randomvar[0] es menor a 6 ó g_randomvar[2] es negativo y g_randomvar[1] es mayor a 25

    
if(g_randomvar[0] < || !g_randomvar[2] && g_randomvar[1] > 25)


Aquí, esta función estaría dando resultados erróneos, porque -1 no es un numero que sea interpretado como negativo en este lenguaje, aparte de eso, puede tirar falsos errores el ANDing de la segunda sentencia, para arreglar esto, debemos ajustarnos a sentenciar exactamente lo que que queremos.

Código PHP:
// Si g_randomvar[0] es menor a 6 ó g_randomvar[2] es negativo (cero) y g_randomvar[1] es mayor a 25

    
if(g_randomvar[0] < || (g_randomvar[2] == && g_randomvar[1] > 25)) 
Ahí estamos interpretando exactamente lo que queremos, entonces no debería de haber problemas a la hora de leer la sentencia.



Nota: Sentencias adjuntas

No se exactamente como se le llama a esto, pero cuando adjuntas varias sentencias en un solo parentesis, estas daran solamente 1 resultado en la misma condición.

Ejemplo:

Código PHP:
new g_randomvar[3]

        
g_randomvar[0] = 0

        g_randomvar
[1] = 1

        g_randomvar
[2] = 0



public fw_AlgunaFuncion(identFloat:magnitud[3])

{

    
// Esta logica dara solamente 2 resultados en el interprete y se lee de esta manera

    // Si g_randomvar[0] es positivo == true

    // si g_randomvar[1] y g_randomvar[2] son positivos == true / de lo contrario si alguno de estos son negativos es false

    
if(g_randomvar[0] || (g_randomvar[1] && g_randomvar[2]))

        

    
// @ Interprete

    
if(true || false)

        
// pls...

    

    

    // Sin anclajes

    
if(g_randomvar[0] || g_randomvar[1] && g_randomvar[2])

        

    
// @ Interprete

    
if(true || false && false// false y false == false.. lol

        // pls...


Estructura de Flujo

Como sabemos, algunas personas diseñan una solución al problema que tienen programando lo que se les vaya saliendo de la mente y irlo desarrollando conforme vayan depurandolo, esto no esta mal, pero nunca ha sido una buena forma de programación, un mejor método de programación, es hacer un diagrama de flujo, donde se pueda ver como funcionara el programa, que rutas tomara en cada caso, que problemas podrían surgir al intentar tomar cada una de las rutas y finalmente como solucionar esos problemas.

Aquí un ejemplo:

Código PHP:
// Alguna función al azar

public fw_EpicFunction()

{

    
// Digamos que segun su estructura, seguira unos cuantos caminos

    
if(/* condicion que siempre tirara true */)

    {

        
// Code pls..

        

        
if(/* Condicion que siempre tirara false*/)

        {

            
// Code pls..

            // ...

            // ....

        
}

        

        
// Un metodo tonto de hacer algo (dense a imaginar que)

        

        
if(/* condicion correctamente usada */)

        {

            
// Code pls..

            // ...

            // ....

        
}

    }


En las funciones que usualmente siempre tiran true/false es suelen ser donde se usan cvars cuyas preferencias siempre quedan en un solo valor, para eso es mejor remover el flujo de condiciones innecesarias y remover el codigo no usado.

--->

Código PHP:
// Alguna función al azar

public fw_EpicFunction()

{

    
/*Suponiendo que borramos un flujo que no es necesario aquí quedaría el codigo de lo que siempre tiraba true */

    

    // Un metodo tonto de hacer algo (dense a imaginar que)

    

    /*Suponiendo que borramos un flujo que no es necesario aquí BORRARIAMOS el codigo de lo que siempre tiraba false */

    

    
if(/* condicion correctamente usada */)

    {

        
// Code pls..

        // ...

        // ....

    
}


Ahí estamos reduciendo su estructura, por ende es mejor pues el procesador lee solamente lo que tiene que leer, a lo que me refiero es que si el flujo de la condición es siempre constante, es mejor borrarlo.



2. Asignación de memoria.

Pros y contras de new y static a petición de Gladius.

new es la forma de declarar una variable en este lenguaje, esta variable segun donde se declare, pasara a ser privada o global, cuando es privada, solamente puede usarse en la funcion donde se declaro y cuando es global puede usarse en cualquier parte, esta cuando es privada, ya no es referenciada y la funcion termina de ejecutarse, es practicamente eliminada de la memoria, cuando es global esta es eliminada de la memoria cuando el mapa se cambia, esta es buena para usarse en funciones que practicamente no se llaman muy seguido, pues la memoria sera liberada al terminar de ejecutar lo que se vaya a hacer, en funciones recursivas tiene un impacto negativo cuando el stack de memoria que declaramos es grande, pues tiene que inicializar cada una de las veces el stack de memoria.



static por su parte, es tambien otra manera de declarar una variable, solo que esta se guarda en memoria y puede cargar los datos aun cuando la funcion no se esta ejecutando, cuando es referenciada, su valor sera el mismo que dejo en la anterior ejecución, esta es una keyword usada para las funciones recursivas, que usualmente requieren estar obteniendo datos, sus pros son que no tiene que ser inicializada, pues una vez creada, reside en memoria y se queda ahi hasta que se cambie el mapa, sus contras es que al crear grandes stacks de memoria, estos se guardan en RAM, dando un impacto negativo en VPS o en PCs de muy bajo rendimiento, pero eso muy poco probable que eso pase.



Código PHP:
// Flujo de variables para dummies (en una función).



// NEW

public func(you_daft_wankerbloody_frog_would_be_more_use_than_you)

{

    
// Inicializa (cada vez que esta funcion sea llamada lo hara).

    
new newtypevar

    

    
// Obtiene datos.

    
get_something(newtypevar)

    

    
// Los manda para algun lado.

    
send_to_somewhere(newtypevar)

    

    
// Se borra.

}



// STATIC

public func(you_daft_wankerbloody_frog_would_be_more_use_than_you)

{

    
// Inicializa.

    
static statictypevar

    

    
// Obtiene datos.

    
get_something(newtypevar)

    

    
// Los manda para algun lado.

    
send_to_somewhere(newtypevar)


Los 2 tienen diferentes usos para lo que se quiere hacer y el error de muchos es asignar memoria que no usan, incrementando el tamaño del plugin y el tiempo en el que el procesador lee cada valor ASCII para interpretarlo como letra (en el caso de cadenas).

Ejemplo:

Código PHP:
// Hook del Mensaje 'SayText' -> register_clcmd("say", "clcmd_sayhook")

// Funcion que se llama cada vez que el usuario escribe algun texto publico.

public clcmd_sayhook(id)

{

    
// Es correcto utilizar static para guardar que dijo en memoria y reemplazarlo cada

    // vez que sea llamada la función.

    
static quedijo[192]

    
read_args(quedijocharsmax(quedijo))

    

    if(
quedijo[0] == '&' || quedijo[0] == '(')

        
// asd..

    

    // asd...


Ahí nuestro error es asignar 192 celdas de memoria cuando solo estamos chequeando 1 sola, esto hace que el procesador tenga que cargar un poco más de datos cuando la variable es referenciada (aunque estos estén en ceros), una solución a esto sería cambiarlo por new (a su gusto y preferencia, pues es un array muy chico) y reducir el tamaño del array a 2, pues ahí estamos gastando exactamente 760 bytes de memoria que podríamos usar en otra operación.



Otro error parecido es que estamos interactuando con alguna cosa que necesita ser chequeada con strings y hacemos esto:

Código PHP:
new const MyString[] = "MyStringTROLOLOL" // <- MyString[17+1] el +1 es por si las dudas.



// llamada 5 veces por segundo..

public fw_SomeRandomFunc()

{

    static 
customstring[64]

    
AlgunaNativaQueObtieneUnString(customstringcharsmax(customstring))

    

    if(
equal(customstringMyString))

        
// pls..

    

    // pls..


No necesariamente algunas cosas necesitan ser chequeadas con strings, hay algunos métodos como utilizar sus valores privados (pev) o incluso darles un id, pero aquí el caso es que estan asignando y chequeando una cadena de 64 caracteres máximos con una que solo tiene 16.. están referenciando memoria innecesaria, mi consejo es que solo usen los caracteres maximos de las cadenas que estan comparando.. si comparan varias cadenas precomputadas, fijense cual es la más grande y establescan ese valor (+1 o +2 celdas para evitar problemas) y así se ahorran unos cuantos kilobytes o incluso megas de memoria.



Otro problemilla puede ser a la hora de hacer menus del viejo estilo, es que tienes que mostrar tu mismo un texto y detectar las teclas presionadas.

Código PHP:
public mostrar_menu_clasico1(id)

{

    static 
menu[1000]

    
// Menu pls..

}



public 
mostrar_menu_clasico2(id)

{

    static 
menu[1000]

    
// Menu pls..

}



public 
mostrar_menu_clasico3(id)

{

    static 
menu[1000]

    
// Menu pls..


Ahí estamos asignando una cantidad enorme y exagerada de memoria.. como formatex no crea un copy-back.. lo más utilizado es usar un lenght para determinar desde donde empieza a escribir nuevos datos (utilizado en ZP), ahí podemos optimizar el codigo creando una sola variable global de 1000 celdas y intercalarla entre todos los menus.

-->

Código PHP:
new g_menu[1000]



public 
mostrar_menu_clasico1(id)

{

    new 
len

    
// Menu pls..

}



public 
mostrar_menu_clasico2(id)

{

    new 
len

    
// Menu pls..

}



public 
mostrar_menu_clasico3(id)

{

    new 
len

    
// Menu pls..


Lo mismo puede ser con otras funciones que hagan lo mismo pero tengan que manejar diferentes textos, ahí simplemente guardan 4kb de memoria en textos y se intercalan entre ellos, siempre y cuando usen el mismo método (el lenght, en este ejemplo), como podría ser un motd (que también puede usar lenght) o un archivo de texto escrito con write_file() tambien usa lenght.



Gracias a stereo por la sugerencia de abajo.

Otro error común es que algunas personas crean un bucle y dentro de el inicializan variables, esto es malo para bucles de gran escala, puesto que cada vez que el bucle se inicia, si se usa new explicado como funciona arriba, tiene el mismo impacto como si fuera una función iterativa (parecida a la recursiva, solo que esta se repite x numero de veces). Cada vez que el bucle se repita, la variable sera creada de nuevo, thus, desgastando al CPU dependiendo del tamaño de las variables, la solución sencilla es declararlas una sola vez FUERA del bucle.



Código PHP:
// Forma asquerosa.

forward func()

{

    while(
false// No quotees esto, no seas el capitan obvio, lo que explico esta abajo v

    
{

        new 
fuckmycpu[400// NOOOOOOOOOOOOOOOO

        

        // ...

    
}

}



// Forma mas o menos

forward func()

{

    new 
softitalil[400]

    

    while(
true// ._.

    
{

        
//...

    
}


3. Estructura teórica

Nota: Esta parte es puro texto aburrido y sin ejemplos, debido a que es una sección individual.

Este probablemente sea el bloque más complicado que habra que repasar, puesto que esto es de cada quien, no quiero que se arme un pedo porque todos tenemos un diferente pensamiento, así que respeten los codigos de otros programadores, por más bonitos o asquerosos que sean.



Cuando tu vas a hacer un plugin, masomenos te das una idea de como lo vas a hacer, que funciones del motor vas a hookear y que vas a hacer con ellas, aquí es donde entra tu estilo, pues cada quien piensa mejor o peor y tiene distintas formas de hacerlo, pero el problema es que lo que queremos es mejorar, entonces que hacemos?



Después de pensar profundamente como va a ser tu plugin tienes entonces ya una parte hecha, la parte teórica, esta viene referenciando a como va a funcionar tu plugin de una manera pensada, sin embargo debemos pensar en todas las cosas posibles que pueden suceder al hacer una cosa, porque como sabemos, generar una respuesta genera muchísimas mas preguntas.



Cuando tengas un plugin teórico este tiene que tener en cuenta los siguientes puntos (avísenme si se me va alguno y NO, no están ordenados)



Método que vamos a usar

Aquí piensas como va a funcionar tu plugin, por ejemplo: Digamos que yo quiero que salte mas alto cuando brinque pero sin ajustar gravedad, voy a hacer esto, esto y eso..

Problemas que podría causar el método que vamos a usar

Es una pre-depuración.. en que podría perjudicar a otros plugins, usando este ejemplo, podría perjudicar al multijump.

Funciones, variables y nativas que usaremos

Suponiendo que usamos lo de arriba, usaremos pev_velocity para establecer una magnitud mas fuerte al salto.

Como podríamos optimizar lo que ya tenemos

Si es que se puede, como se puede mejorar lo que ya esta hecho.

Flujo continuo del plugin

Eliminar las cosas que de plano no usaremos mucho y que afectan la velocidad del plugin por más mínima que sea esta, recuerden que les puede pasar como a mí, que los detalles siempre terminan dándome un cáncer

Depuración (este se podría decir que es después de hacer el plugin)

Arreglar los bugs que se reporten de este ya sea en el mismo juego o en alliedmods, si es que es publico





Una vez que tengamos esto podemos pasar a crear el plugin, pero ojo aquí para eso esta alliedmodders, para cuando tu no puedas pensar por tu cuenta alguno de los siguientes puntos, todos los de la comunidad puedan ayudarte ya sea cuando estés haciéndolo o cuando todavía este en esta fase..



4. Reducción de instrucciones

Cuando ya tienes un codigo más o menos limpio, otra forma de reestructurarlo para que este sea más fluido es intentando reducir las lineas de codigo por argumentos sencillos y menos lineas de codigo, así los lectores del codigo fuente se estresan menos.



Un ejemplo sería a la hora de emplear strings, tenemos una variable que decidira lo que se mostrara en pantalla, pero tipicamente muchas personas usarian un if, cuando realmente es cuestion de utilizar una sentencia pegada a la nativa que llamaremos.



Código PHP:
// Dummy way

public somerandomjunk(idive_meet_smarter_donkeys_than_you_lot)

{

    new 
derP

    

    
// Junky code..

    

    
if(derP == 2)

        
client_print(idprint_center"What a plonker!")

    else if (
derP == 5)

        
client_print(idprint_center"I've meet smarter donkeys than you lot!"// lol taba sola

    
else

        
client_print(idprint_center"You daft wanker!")


Esto se puede reducir a una simple linea, un poco larga pero más sencilla de leer.



Código PHP:
public somerandomjunk(idive_meet_smarter_donkeys_than_you_lot)

{

    new 
derP

  

    
// Junky code..

    

    
client_print(idclient_print"%s"derP == "I've meet smarter donkeys than you lot!" derP == "What a plonker!" "You daft wanker!")


Con esto reducimos lineas y ahorramos un poco de lectura, en optimización no influye mucho, pero es más para que sea un buen habito.



Siempre hay que tratar de que las instrucciones sean las menores posibles y que obtengan el resultado que quieres.



Ay luego le sigo añadiendo cosas.. se aceptan comentarios y diganme si les gustan mis consejos y en que se pueden mejorar.
[Imagen: 76561198024598105.png]
Responder
#2
Soy yo o se tabuleo mal los codigos en PHP ?

Ando en movil
Todos los MODS VHL totalmente gratuitos  Descarga Aqui

Mis plugins:
STEAM: https://steamcommunity.com/id/Metrikcz/
FB: fb.com/rwoong
Venta plugins a pedido en México mándame MP
Responder
#3
Nunca habia visto este post en AM, cuando tenga tiempo lo leo completo para mejorar mis códigos.

Gracias por compartilo

Ni te molestes en enviarme un mensaje privado para pedirme ayuda porque NO lo voy a contestar.
Gracias por su atención.
Responder
#4
Gracias por compartir!!



Está bueno traer los post de am acá, como para que empiezen a recurrir mas a este foro...
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)