[GUIA] Mantener una gamemode bien estructurada

Aprende lo que no sabes de este lenguaje y encuentra herramientas y códigos útiles.

Moderador: Ayudantes

Reglas del Foro
  • Si tu código es corto, no crees un tema nuevo para liberarlo, publica un mensaje en el tema [Funciones] ¡Publica tu código aquí!.
  • Si creas una guía, debes explicar el código claramente. Evita poner la explicación en forma de comentarios dentro del mismo y no olvides utilizar el BBCode correspondiente: [Pawn]Código aquí[/Pawn].
  • No postear códigos sin probar. Publicar códigos con errores (que impidan compilar el script para el cual está destinado) en este apartado es motivo de sanción.
  • Si tu código necesita plugins, includes u otros códigos adicionales para funcionar, debes mencionarlo en el mensaje.
  • Si has utilizado códigos de otros autores, recuerda colocar los créditos correspondientes. (El plagio es motivo de sanción).
  • Si tu aporte es para un GameMode en específico, debes publicar el tema en el apartado "Guías y Aportes para GameModes específicos".
Responder
Omaretot
Aprendiz
Aprendiz
Mensajes: 95
Registrado: 07 Dic 2015 18:46
Reputación: 7

25 Abr 2018 13:49

Una de las cosas que he notado de muchas de las gamemode es que mantienen una estructura mal realizada, por ejemplo muchos "new" declarados, mala organización, un comando en el top de la GM y otro al final y se ve realmente MAL a la hora de realizar una gamemode.

Lo primero que deberemos saber es que en esta guía mantendremos un nivel de conocimiento básico y unos consejos a los que piensan realizar una gamemode desde 0.

1. El primer consejo que deberemos tener en cuenta que todo buen programador tiende además de una buena organización la manía de tener que programar en INGLES y la interfaz en el idioma en el cual se estara realizando la gamemode, por ejemplo, debes programar en ingles pero si deseas abrir un servidor para la comunidad hablahispana la interfaz o los mensajes o mejor dicho lo "visual" puedes hacerlo en español, si vas a hacer un servidor para la comunidad rusa deberás hacer tu programación en ingles pero los mensajes y demás en ruso.

Ahora te preguntaras ¿Por qué?, la respuesta es muy simple, ya que a la hora de que otro programador vaya a leer tu codigo sea ENTENDIBLE para todos ya que el inglés es el idioma más utilizado en el mundo. En caso que sea una programación privada también se recomienda programar en ingles ya que la mayoria de los programas de programación estan en ingles.

2. Mantener una estructura, con eso me refiero a que debes poner cada cosa en su lugar, por ejemplo los defines en un lugar, los enum en otro, los stocks en otro lugar, los comandos en otro lugar y tener 10 callbacks sin utilizar haciendo de adorno, en mi caso me gusta tener todo organizado, todo junto para cuando vaya a buscar algo se me sea mucho más sencillo, aquí también me gustaría agregar una punto adicional es que siempre se debe agregar un comentario o el " // " a la mayoria de las cosas, ya que aunque uno haga las cosas y tengas un codigo largo no te acordaras y no sabras para que sirve esa función. En mi caso para el punto 2 me gusta llevar el orden de:

- Includes.
- Defines.
- Enums.
- News.
- Callbacks.
- Callbacks de Timers.
- Comandos.
- Stocks.
- Otros.

3. Reducir el número de "news" lo más posible y pasarlos a "enum", hace que el script se vea mucho más organizado y limpio, Ejemplo:
 Codigo Pawno:
1
2
3
4
5
6
7
8

new CanalBloqueado;
new CanalDudasBloqueado;
new CanalPrivadoBloqueado;
new Callado[MAX_PLAYERS];
new Congelado[MAX_PLAYERS];
new PuedeRolear[MAX_PLAYERS];
new EstaLogeado[MAX_PLAYERS];
new Warneado[MAX_PALYERS];
  Cantidad de llaves: Abiertas(0)-Cerradas(0) | Lineas Totales: 8
Lo podemos pasar a enums así:
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11
12

enum E_BLOCK_INFO {
    E_BLOCK_CHAT,
    E_BLOCK_QUESTIONS,
    E_BLOCK_PM,
}

enum E_PLAYER_SESSION {
    E_PLAYER_FREEZED[MAX_PLAYERS],
    E_PLAYER_MUTED[MAX_PLAYERS],
    E_PLAYER_LOGED[MAX_PLAYERS],
    E_PLAYER_WARNED[MAX_PLAYERS],
}
  Cantidad de llaves: Abiertas(2)-Cerradas(2) | Lineas Totales: 12
]

Un dato adicional que me gustaria dar es muchas personas en el guardado de datos de los jugadores utilizan mucho el pInfo, pues los invito a ustedes a que cambie sus datos y mantener una buena organización del guardado de datos del jugador:
 Codigo Pawno:
1
2
3
4
5
6
7

enum E_PLAYER_INFO {
    E_PLAYER_PASSWORD,
    E_PLAYER_ADMINISTRATOR,
    E_PLAYER_POSITION,
    E_PLAYER_SKIN,
    E_PLAYER_LEVEL,
}
  Cantidad de llaves: Abiertas(1)-Cerradas(1) | Lineas Totales: 7
Una cosa muy importa que quiero dejar en claro es que no confundan los datos del jugador con los datos de la sesion del jugador, ¿A qué me refiero con la sesión del jugador?, me refiero a la información del jugador mientras este conectado, por ejemplo si esta congelado, callado, advertido, una cosa muy importante es separar los datos que guardaras y los datos que no, por ejemplo en el enum E_PLAYER_SESSION son los datos que no guardaremos, pero en el enum E_PLAYER_INFO si los guardaremos, obviamente eso depende de cada sistema de registro/logueo de cada gamemode.

4. Dividir la gamemode, este paso solo es para gamemodes GRANDES y con muchos sistemas complejos, dividir la gamemode en include, creamos una carpeta con el nombre del servidor y dividimos en tantas carpetas sea necesario, en mi caso utilizare 5 carpetas que se llamaran:
- Utils // Utilidades, aquí guardamos normalmente los comandos, dialogos, entre otros
- User // Usuarios, aquí estara los datos del jugador y el sistema de guardado/cargado
- Engine // Motor, aquí se iniciara el servidor
- Editor // Editor, en mi gamemode tengo un editor de misiones.
- Core // Nucleo, aquí iran las cosas más importantes y de que consistira el servidor, en mi caso dentro guardare mis include de objetivos, misiones, mapeos y actores que serán lo más importantes.

Es importante que este ultimo paso es recomendado solo PARA gamemodes grandes Y PROGRAMADORES PROFESIONALES/EXPERIMENTADOS, se volveran un caos los novatos en realizar este ultimo paso.

Saludos:)
ChrisPa
Mensajes: 101
Registrado: 19 Abr 2018 20:37
Ubicación: Mexico
Contactar:
Reputación: -5

25 Abr 2018 14:04

Buen aporte para los nuevos en pawn
Si te ayude por favor déjame +1 =) Se agradece, yo are lo mismo cuando tu me ayudes

Avatar de Usuario
MrDave
Ayudante
Ayudante
Mensajes: 1049
Registrado: 05 Oct 2017 12:13
Reputación: 113

25 Abr 2018 15:33

- El tercer paso no te hace ver el código más legible. Esto dependerá de la manera como trabaje el programador.
1 Forma:
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11

enum @DATA
{
	KILLS,
	DEATHS,
	SCORE,
	MONEY,
	LEVEL,
	LEVEL_VIP
};

new Info[MAX_PLAYERS][@DATA];
  Cantidad de llaves: Abiertas(1)-Cerradas(1) | Lineas Totales: 11
2 Forma:
 Codigo Pawno:
1
2
3
4
5
6

new KILLS			[MAX_PLAYERS];
new DEATHS			[MAX_PLAYERS];
new SCORE			[MAX_PLAYERS];
new MONEY			[MAX_PLAYERS];
new LEVEL			[MAX_PLAYERS];
new LEVEL_VIP		[MAX_PLAYERS];
  Cantidad de llaves: Abiertas(0)-Cerradas(0) | Lineas Totales: 6
Ambas formas son equivalentes y se ve organizado.

- El último paso no es el más difícil, al contrario es factible sí sólo se quiere insertar funciones, variables o procedimientos en una librería, porqué sí se quiere crear un sistema complejo, por ejemplo: Un sistema de carreras, hay que saber hacer el "hook" (enganche a funciones).
¿Por qué es necesario?
Sí necesitas usar la función pública "OnPlayerConnect" en tu librería y ya está en uso en mi archivo principal (modo de juego), no sería posible tener dos funciones con el mismo nombre en ambos archivos, el compilador daría un error de sintaxis diciendo: "Ya está definido "OnPlayeConnect"".
Aquí daré un ejemplo sencillo:
Vamos a suponer que tenemos creado un archivo externo llamado "mi_libreria" y será incluido con la directiva "#include" en mi "gamemode"
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

#include <a_samp.inc>
#include <mi_libreria.inc>

main()
{
	print("Modo de juego FREEROAM - Cargado con éxito");
	return 0;
}

public OnPlayerConnect(playerid)
{
	SendClientMessage(playerid, -1, "¡Bienvenido al servidor!");
	return 1;
}
  Cantidad de llaves: Abiertas(2)-Cerradas(2) | Lineas Totales: 14
Y en mi archivo "mi_libreria" vamos agregar un mensaje cuando el administrador RCON se conecte.
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

forward _H_OnPlayerConnect(playerid);

public OnPlayerConnect(playerid)
{
	if(IsPlayerAdmin(playerid))
	{
		SendClientMessage(playerid, -1, "¡Bienvenido administrador RCON!");
	}
	return _H_OnPlayerConnect(playerid);
}
#if !defined _ALS_OnPlayerConnect
	#define _ALS_OnPlayerConnect
#else
	#undef OnPlayerConnect
#endif
#define OnPlayerConnect _H_OnPlayerConnect
  Cantidad de llaves: Abiertas(2)-Cerradas(2) | Lineas Totales: 16
Tengo que recalcar, que aquí usé el método ALS (Advanced Library System) 7, esto se lo emplea para verificar sí esa dicha función ha sido enganchada en otra librería, porqué sino el compilador tiraría una advertencia diciendo: "Hay una re definición de 'X' símbolo", obviamente el mensaje sería en inglés.

- Temporalmente estoy retirado de SA-MP; por lo tanto no me envíen propuestas de proyectos.
- No respondo dudas por privado, usa la sección de preguntas.
Avatar de Usuario
Alfon
Baneado
Baneado
Mensajes: 693
Registrado: 17 Ene 2016 18:39
Ubicación: YOVIVOENALGUNAPARTEDEESTE INSIGNIFICANTEMUNDOLLENODE RARITOSYANORMALES PERONOPASANADACARNAL YOLOSAMO
Reputación: 24

25 Abr 2018 19:40

Spoiler:
MrDave escribió:
25 Abr 2018 15:33
- El tercer paso no te hace ver el código más legible. Esto dependerá de la manera como trabaje el programador.
1 Forma:
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11

enum @DATA
{
	KILLS,
	DEATHS,
	SCORE,
	MONEY,
	LEVEL,
	LEVEL_VIP
};

new Info[MAX_PLAYERS][@DATA];
  Cantidad de llaves: Abiertas(1)-Cerradas(1) | Lineas Totales: 11
2 Forma:
 Codigo Pawno:
1
2
3
4
5
6

new KILLS			[MAX_PLAYERS];
new DEATHS			[MAX_PLAYERS];
new SCORE			[MAX_PLAYERS];
new MONEY			[MAX_PLAYERS];
new LEVEL			[MAX_PLAYERS];
new LEVEL_VIP		[MAX_PLAYERS];
  Cantidad de llaves: Abiertas(0)-Cerradas(0) | Lineas Totales: 6
Ambas formas son equivalentes y se ve organizado.

- El último paso no es el más difícil, al contrario es factible sí sólo se quiere insertar funciones, variables o procedimientos en una librería, porqué sí se quiere crear un sistema complejo, por ejemplo: Un sistema de carreras, hay que saber hacer el "hook" (enganche a funciones).
¿Por qué es necesario?
Sí necesitas usar la función pública "OnPlayerConnect" en tu librería y ya está en uso en mi archivo principal (modo de juego), no sería posible tener dos funciones con el mismo nombre en ambos archivos, el compilador daría un error de sintaxis diciendo: "Ya está definido "OnPlayeConnect"".
Aquí daré un ejemplo sencillo:
Vamos a suponer que tenemos creado un archivo externo llamado "mi_libreria" y será incluido con la directiva "#include" en mi "gamemode"
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

#include <a_samp.inc>
#include <mi_libreria.inc>

main()
{
	print("Modo de juego FREEROAM - Cargado con éxito");
	return 0;
}

public OnPlayerConnect(playerid)
{
	SendClientMessage(playerid, -1, "¡Bienvenido al servidor!");
	return 1;
}
  Cantidad de llaves: Abiertas(2)-Cerradas(2) | Lineas Totales: 14
Y en mi archivo "mi_libreria" vamos agregar un mensaje cuando el administrador RCON se conecte.
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

forward _H_OnPlayerConnect(playerid);

public OnPlayerConnect(playerid)
{
	if(IsPlayerAdmin(playerid))
	{
		SendClientMessage(playerid, -1, "¡Bienvenido administrador RCON!");
	}
	return _H_OnPlayerConnect(playerid);
}
#if !defined _ALS_OnPlayerConnect
	#define _ALS_OnPlayerConnect
#else
	#undef OnPlayerConnect
#endif
#define OnPlayerConnect _H_OnPlayerConnect
  Cantidad de llaves: Abiertas(2)-Cerradas(2) | Lineas Totales: 16
Tengo que recalcar, que aquí usé el método ALS (Advanced Library System) 7, esto se lo emplea para verificar sí esa dicha función ha sido enganchada en otra librería, porqué sino el compilador tiraría una advertencia diciendo: "Hay una re definición de 'X' símbolo", obviamente el mensaje sería en inglés.
Opino lo mismo que vos.

Yo por ejemplo, me acostumbré a scriptear de otra forma a como suelen hacer la mayoría.
Avatar de Usuario
MattHudson
Moderador Global
Moderador Global
Mensajes: 1666
Registrado: 31 Oct 2015 18:16
Ubicación: Argentina, Buenos Aires, San Miguel.
Contactar:
Reputación: 89

25 Abr 2018 22:48

Esta bueno el punto de vista, te llevas un +1 de mi parte por la voluntad de redactar todo el post.

Gustos son gustos, yo soy partidario de poner defines, funciones, variables, algunos callbacks, timers, y cosas así en archivos(includes). Me ahorro lineas del archivo del gamemode y si tengo que buscar algo se donde si es que no me acuerdo el lugar del gamemode. Me acuerdo que cuando empece en Pawn estaba hora buscando cosas escritas por mi en un gamemode liberado, hasta que empece a señalar todo con comentarios al estilo..."Comandos agregados por Matt", "Funciones agregadas por Matt", "Variables agregadas por Matt", y así tardaba segundos en encontrar el código que yo escribía. Hasta que tuve la oportunidad de empezar a usar editores de código como Sublime Text para brindarme un salto para poder dividir mi código en diferentes archivos. Me sentía super cómodo a la hora de programar.



Un saludo!.
JuanS
Avanzado
Avanzado
Mensajes: 821
Registrado: 05 Sep 2014 08:14
Reputación: 37

26 Abr 2018 08:45

1) Completamente de acuerdo, no debería existir el espanglish, todo en ingles o todo en español pero sólo 1.

2) Aclarar que SA-MP no especifica una estructura de programación para los servidores, aquí puedes agregar un trozo de código dónde tú quieras y no tendrás problemas con el compilador(excepto por definiciones, variables y librerías), por ejemplo, en Pawn puedo utilizar una función antes de haberla agregado al script, -2-uso -1-definición, cuándo debería de ser -1- y después -2-, me gustaría ver si pueden hacer eso, por ejemplo en C++(No se puede, se debe agregar primero la función y después puedes utilizarla).

La palabra 'stock' tiene un uso especifico "No compilar variables y funciones que no se utilizan", se puede utilizar para crear librerías no en un gamemode, al menos que quieras hacer lo que dije antes (sin lógica, lo eliminas y ya). Las funciones no necesitan de 'stock'.

3) ¿Sabias que son más rápidas las variables normales que las variables con enumeradores?

4) Se llama "Programación modular" y no es tan difícil cómo parece(así trabajo yo, con programación modular). IDE que permita abrir varios archivos al mismo tiempo y muchos hook's, esto es todo lo que se necesita.

MrDave escribió:
25 Abr 2018 15:33
- El tercer paso no te hace ver el código más legible. Esto dependerá de la manera como trabaje el programador.
 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10

enum @DATA
{
	KILLS,
	DEATHS,
	SCORE,
	MONEY,
	LEVEL,
        LEVEL_VIP
};
new Info[MAX_PLAYERS][@DATA];
  Cantidad de llaves: Abiertas(1)-Cerradas(1) | Lineas Totales: 10
¿Sería VIP_LEVEL, no? Precisamente estamos debatiendo sobre el espanglish y sus parecidos, ésto también es algo muy común en el foro, si quieren programar algo que van a liberar, deben hacerlo de la mejor manera posible para que las otras personas entiendan el código, una persona que habla inglés no buscara "LEVEL_VIP" porque está mal. Si no entiendo el inglés completamente, lo hago en español mejor -mfr_lol

Sobre el hook, veo que recomiendas mucho YSI, ¿por qué mejor no con yhooks?

 Codigo Pawno:
1
2
3
4
5
6
7
8
9
10

#include <YSI\y_hooks>

hook OnPlayerConnect(playerid)
{
    if (IsPlayerAdmin(playerid))
    {
        SendClientMessage(playerid, 0xFFFFFFFF, "¡Bienvenido al servidor!");
    }
    return 1;
}
  Cantidad de llaves: Abiertas(2)-Cerradas(2) | Lineas Totales: 10
¡Buena guía!
Servicio de scriping Pawn profesional.

Beneficios:

• Código estructurado y bien escrito.
• Variables y funciones debidamente nombrados.
• Código optimo y eficiente.
• Uso adecuado de la lengua inglés.
• Servicio rápido.


Importante:

Al comprar el código es completamente suyo.
No hay créditos necesarios y la edición/liberación es completamente su problema.


Enviame un pm aquí, con información y el propósito de tu script y yo voy a responder con la información requerida en tu mensaje.
Qarper
Aprendiz
Aprendiz
Mensajes: 9
Registrado: 25 Dic 2015 22:52
Ubicación: Viviendo en Argentina
Reputación: 0

30 Abr 2018 00:19

Veo bastante sucio utilizar includes/plugins (además de los necesarios y cómodos para programar: streamer, mysql, sscanf y algún procesador de comandos). Observé un modo de juego que liberaste y no sé si soy yo (que soy el más obsesivo de los obsesivos), pero no estaba para nada ordenado. Te felicito, fue una guía entretenida.
Omaretot
Aprendiz
Aprendiz
Mensajes: 95
Registrado: 07 Dic 2015 18:46
Reputación: 7

30 Abr 2018 05:45

Qarper escribió:
30 Abr 2018 00:19
Veo bastante sucio utilizar includes/plugins (además de los necesarios y cómodos para programar: streamer, mysql, sscanf y algún procesador de comandos). Observé un modo de juego que liberaste y no sé si soy yo (que soy el más obsesivo de los obsesivos), pero no estaba para nada ordenado. Te felicito, fue una guía entretenida.
Buenas,

Amigo, como mencione en el tema ese proyecto esta descontinuado, la ultima vez que lo toque no sabia ni la mitad de lo que hay en esta guia, capaz en una R2 que haga (Que no creo que haga) le repare todo sus bugs y re-estructure por completo la gamemode, saludos.
Responder