Brazil
CodeFactory ®


Desenvolvendo DLLs para o PMS - Módulo 2

Bom, continuando de onde eu parei no módulo 1.

Hoje eu vou começar o módulo falando um pouco sobre o fluxo de dados no GameServer, como eles chegam e como eles saem, só as noções, para vocês saberem como vamos trabalhar daqui pra frente!

Para começo de conversa, o GameServer recebe os dados através de IOCP, isso vocês podem pesquisar informações na internet, mas é irrelevante no momento para que não tem muito conhecimento sobre programação, depois de recebidos e tratados os dados, eles vão parar no ProtocolCore do GameServer, já decriptados os packets C3 e C4.
No ProtocolCore, esses dados vão passando pelas funções que o GameServer tem, o GameServer faz os tratamentos que esse packet pediu para ele fazer, e envia um packet com uma resposta para o client.

De curto e grosso modo é isso. Agora, o que nos importa, é saber como nós vamos pegar esses dados, se vocês prestaram atenção na DLL Custom e no módulo anterior de nosso curso, vocês devem ter notado que existe uma função chamada de ProtocolCoreEx na base que eu postei. Esse sufixo Ex vem de "externo", esse ProtocolCoreEx da DLL que você está programando recebe os dados antes do GameServer, e é aí que nosso código é capaz de interceptá-lo e interpretá-lo de modo que possamos modificar atributos do personagem, criar comandos e etc.

Isso é só uma seção "Noção básica de como o troço funciona". Para se aprofundar mais, vocês precisam aprender a análisar packets, que é coisa que não se aprende com outras pessoas, só na base do "vai lá e tenta".

Agora a segunda parte do tópico que eu queria comentar é sobre as funções que vocês têm disponíveis na DLL base que vocês usarão para desenvolver seus próprios plugins, no módulo 1 eu usei funções do GameServer e da classe de objetos, mas nem expliquei qual o efeito delas, e é o que vou abordar agora.

Vamos começar pela classe C_OBJECT:

Código:
class _declspec(dllimport) C_OBJECT
{
public:
	int GetIndex();

	int GetConnectStatus();
	
	char * GetAccountId();

	char * GetName();

	int GetMoney();
	void SetMoney(int Value);

	short GetLevel();
	void SetLevel(short Value);

	unsigned short GetClass();
	void SetClass(unsigned short Value);

	unsigned char GetDbClass();
	void SetDbClass(unsigned char Value);

	unsigned short GetLevelUpPoints();
	void SetLevelUpPoints(unsigned short Value);

	short GetStrength();
	void SetStrength(short Value);

	short GetAgility();
	void SetAgility(short Value);

	short GetStamina();
	void SetStamina(short Value);

	short GetEnergy();
	void SetEnergy(short Value);

	unsigned char GetMapNumber();
	unsigned short GetXPosition();
	unsigned short GetYPosition();

	void PkLevelSend(unsigned char PkLevel);
	void MoneySend(unsigned int Amount);
	void TeleportPos(int MapNumber, int PositionX, int PositionY);
	void LevelUpSend(unsigned short Level, unsigned char LevelUpPoint, unsigned short MaxLife, unsigned short MaxMana);
	void InventoryUpdateItem(unsigned char ItemPosition);
	void InventoryDeleteItem(unsigned char ItemPosition);
};
A classe C_OBJECT é uma ponte entre o plugin e a OBJECTSTRUCT que tem "dentro" do GameServer. O motivo de eu ter usado essa ponte e não a OBJECTSTRUCT em si é pelo fato de que explicar o funcionamento da OBJECTSTRUCT e a forma como é diferente de GameServer para GameServer pode ser uma tarefa difícil, e mais difícil ainda é um marinheiro de primeira viagem entender isso, portanto eu criei essa ponte, que simplifica o caminho para vocês começarem.

Nesse módulo nós não vamos criar código nenhum, vamos apenas estudar o que faz cada uma dessas funções acima e como devemos usá-las corretamente.

Eu dividi elas em 3 tipos de funções, as funções Get, as funções Set e as funções Send, vou começar explicando qual a diferença básica entre cada uma delas.

As funções Get são funções que capturam valores da ObjectStruct, elas pegam o valor de determinados atributos de um personagem e retornam esses valores para serem usados em alguma função.

As funções Set servem para INSERIR valores na ObjectStruct, ou seja, com ela você é capaz de modificar atributos de um personagem por exemplo.

E por fim as funções Send são as funções que enviam dados para o client, eu quis deixar isso bem claro porque as funções Get e Set NÃO ATUALIZAM AS INFORMAÇÕES DO PERSONAGEM NO CLIENT, já as funções Send sim.

Vamos ver agora um pouco sobre as variáveis mais comuns do C++:
Código:
variáveis signed: Essas variáveis possuem sinal (positivo / negativo)
int: Armazena um número inteiro entre -2bilhões e +2bilhões (Tamanho: 4 bytes)
short: Armazena um número inteiro entre -32768 e +32767 (Tamanho: 2 bytes)
char: Armazena um número inteiro entre -128 e 127 (Tamanho: 1 byte)

variáveis unsigned: Essas variáveis não possuem sinal ("un" signed)
unsigned int: Armazena um número inteiro entre 0 e +4bilhões (Tamanho: 4 bytes)
unsigned short: Armazena um número inteiro entre 0 e +65535 (Tamanho: 2 bytes)
unsigned char: Armazena um número inteiro entre 0 e +255 (Tamanho: 1 byte)

variáveis de ponto flutuante:
float: Armazena número fracionário com precisão de até 7 dígitos depois da vírgula (Tamanho: 4 bytes)
double: Armazena número fracionário com precisão de até 15 dígitos depois da vírgula (Tamanho: 8 bytes)

Variáveis ponteiro:
Todas as variáveis ponteiro ocupam 4 bytes de espaço (Quando o programa for de 32bits),
pois elas não armazenam dados como as outras, elas armazenam endereços de memória,
esses endereços "apontam" (daí ponteiros) para blocos de memória
(de tamanho igual ou maior que a variável).

Estudar ponteiros é de nível bem complexo de programação, vamos deixar para depois! ;D

Por ultimo a variável booleana:
bool: Essa variável é julgada como verdadeiro ou falso (true e false) que são, numéricamente falando, 0 e diferente de 0. (Tamanho: 1 byte)
Tendo em mente os tipos básicos de variáveis usadas em C++, vamos à estrutura de uma função:

void Funcao(int x, char y)

1. "void" -> Este é o typedef da função, ele mostra o tipo de retorno que tem a função, se ela retorna um int, significa que ao ser executada, ela vai retornar um valor entre -2 bilhões e 2 bilhões que você poderá usar, o tipo void, como a do meu exemplo, não tem retorno, por isso as funções do tipo Set são todas void, elas não retornam nada!

2. Funcao -> Este é o nome da função, C++ é case sensitive (sensível a maiúsculas e minúsculas, portanto os nomes das funções têm que ser escritos sempre igual para que funcione corretamente).

3. Lista de argumentos -> Aqui é definido os números que precisam entrar em uma função para ela ser executada, se a lista de argumentos for (), significa que não requer argumentos. Se ela possuí argumentos significa que você não pode usá-la sem os mesmos, e, se ela tiver um "...", significa que você pode enviar uma lista de argumentos, geralmente é usado esse modelo para funções que usam textos.

Como usar uma função:
Para usar a função é muito simples, se temos que a função é:
void Funcao(int x, char y)
para chamá-la, basta colocar dessa forma:
Funcao(arg1, arg2);

Não se esquecendo que os typedefs (int, void, char e etc) devem desaparecer, e deverá aparecer ao fim da linha um ";", isso para qualquer tipo de função, é padrão no C++!

Nesse modelo, arg1 e arg2 podem ser variáveis ou algo do tipo, poderiam ser substituídos por números.

Agora que você já tem uma básica noção sobre funções, vamos às que temos disponíveis:
Código:
int GetIndex() : Função retorna o Index do personagem OU monstro.

int GetConnectStatus() : Função retorna o Status da Conexão do Player:
Ela possuí os seguintes retornos:
0 -> Conta offline
1 -> Conta Na tela de Login / Password
2 -> Conta Na tela de select char
3 -> Conta com personagem dentro do jogo.

char * GetAccountId() : Função retorna "Account Id".

char * GetName() : Função retorna Nome do personagem conectado.

int GetMoney() : Função retorna quantidade de Zen do personagem.

void SetMoney(int Value): Função altera quantidade de Zen do personagem:
Essa função leva o argumento Value com ela, nesse caso, Value é a quantidade desejada de Zen.

short GetLevel() : Função retorna Level do personagem.

void SetLevel(short Value): Função altera Level do personagem:
Essa função leva o argumento Value com ela, nesse caso, Value é o level desejado.

unsigned short GetClass() : Função retorna Classe do personagem/mob.

void SetClass(unsigned short Value): Função altera Classe do personagem/mob:
Essa função leva o argumento Value com ela, nesse caso, Value é a classe desejada.

unsigned char GetDbClass() : Função retorna Classe do personagem. (DK, Elf...)

void SetDbClass(unsigned char Value): Função altera Classe do personagem:
Essa função leva o argumento Value com ela, nesse caso, Value é a classe desejada.

unsigned char GetLevelUpPoints() : Função retorna número de pontos do personagem.

void SetLevelUpPoints(unsigned short Value): Função altera pontos do personagem:
Essa função leva o argumento Value com ela, nesse caso, Value é a quantidade de pontos desejada.

short GetStrength(),
short GetAgility(),
short GetStamina(),
short GetEnergy():

Cada uma dessas funções retorna um atributo de um personagem.

void SetStrength(short Value),
void SetAgility(short Value),
void SetStrength(short Value),
void SetEnergy(short Value):

Cada uma dessas funções altera um atributode um personagem, o argumento Value refere-se
à quantidade de pontos desejada para o atributo.

unsigned char GetMapNumber(): Retorna o número do mapa do personagem.
unsigned char GetXPosition(): Retorna a posição X do personagem.
unsigned char GetYPosition(): Retorna a posição Y do personagem.

Daqui para baixo, todas as funções são do tipo Send:

void PkLevelSend(unsigned char PkLevel):
Altera e atualiza as informações de PK do personagem no GS/Client, o argumento PkLevel, pode ser:
1 -> "Hero lvl2"
2 -> "Hero lvl1"
3 -> Commoner
4 -> Pk lvl1
5 -> Pk lvl2
6 -> Murderer

void MoneySend(unsigned int Amount):
Altera e atualiza as informações de Zen do personagem no GS/Client, o argumento Amount
corresponde à quantidade de zen desejada.

void TeleportPos(int MapNumber, int PositionX, int PositionY):
Teleporta o personagem para outra posição, os argumentos referem-se a:
MapNumber: Mapa destino do personagem.
PositionX: Posição X destino do personagem.
PositionY: Posição Y destino do personagem.

void LevelUpSend(unsigned short Level, unsigned char LevelUpPoint, unsigned short MaxLife, unsigned short MaxMana):
Atualiza o Level do personagem no GS/Client e mostra efeitos no client, os argumentos referem-se a:
Level: Level alvo para o personagem.
LevelUpPoint: Quantidade de pontos para o personagem.
MaxLife: Life Máximo novo do personagem (disponível no próximo update função Get e Set).
MaxMana: Mana Máxima nova do personagem (disponível no próximo update função Get e Set).

As funções abaixo vou abordar só futuramente pois referem-se a alterações na ItemStruct do GS:

void GetInventoryItemInfo(unsigned char Position, ITEM_PMS_STRUCT * Buffer);
void SetInventoryItemInfo(unsigned char Position, ITEM_PMS_STRUCT * Buffer);
void InventoryUpdateItem(unsigned char ItemPosition);
void InventoryDeleteItem(unsigned char ItemPosition);
Uma observação interessante, diferente dos modos mais comuns de programação, neste caso você não está trabalhando com variáveis, mas sim com funções, para alterar, por exemplo, o Zen do personagem, faça:
gObj->SetZen(gObj->GetZen() - 1000);

o gObj->GetZen() interno pega o zen do personagem, depois subtraí-se 1000 dessa quantidade, e a função SetZen altera o zen.

Agora vamos falar das funções da class C_GSFUNCTIONS, que possuí atalhos que simplificam o uso de funções, sem a necessidade de declarar offsets e coisas do tipo na DLL.

Código:

class _declspec(dllimport) C_GSFUNCTIONS
{
public:
void DataSend(C_OBJECT * Target, unsigned char * Packet, int Size):
Envia um pacote de dados para o usuário alvo, os argumentos referem-se a:
Target: Conta destino.
Packet: Dados a serem mandados.
Size: Tamanho do packet.

void DataSendAll(unsigned char * Packet, int Size):
Envia um pacote de dados para todos os jogadores, os argumentos referem-se a:
Packet: Dados a serem mandados.
Size: Tamanho do packet.

void LogAdd(unsigned char Color, char * Text,...):
Adiciona na tela do GS log colorido, os argumentos referem-se a:
Color: Cor, vai de 0 a 7 se não me engano, cada um com uma cor diferente, testem! :P
Text: Texto a ser adicionado.
...: Argumentos extras para adicionar dados no texto (como já falei no módulo 1).

void MsgSendAnnounce(C_OBJECT * Target, char *Message,...),
void MsgSendNormal(C_OBJECT * Target, char * Message,...):
Envia uma mensagem para um personagem, os argumentos referem-se a:
Target: Personagem que vai receber a mensage.
Message: a Mensagem.
...: Argumentos extras para adicionar dados no texto.

void MsgSendAnnounceMap(char Map, char *Message, ...),
void MsgSendNormalMap(char Map, char * Message,...):
Envia uma mensagem para todos os personagem online num mapa, os argumentos referem-se a:
Map: Número do mapa no qual os players receberão a mensagem.
Message: a Mensagem.
...: Argumentos extras para adicionar dados no texto.

void MsgSendAnnounceAll(char *Message, ...),
void MsgSendNormalAll(char *Message, ...):
Envia uma mensagem a todos os jogadores, os argumentos referem-se a:
Message: a Mensagem.
...: Argumentos extras para adicionar dados no texto.

Nas funções acima, as que começam com MsgSendNormal, enviam mensagem normal, no canto da tela, já as que começam com MsgSendAnnounce, enviam como o comando "!" de GM.

void MsgSendYellow(C_OBJECT * Target,char* Message, ...):
Envia uma mensagem global no formato do /post com nome do personagem para todos os players.
Target: Quem está enviando.
Message: a Mensagem.
...: Argumentos extras para adicionar dados no texto.

};
E deixo aí o material para vocês que podem se tornar nossos futuros programadores da comunidade, unindo o conteúdo deste post com o do post anterior, já dá pra vocês elaborarem pequenas funções que modificam o estado do jogo, para irem se divertindo um pouco enquanto não venho com o próximo módulo, onde vamos criar um NPC de Reset simples para nossa primeira DLL séria, CustomNPC.dll.

PS. Não deixem de usar o novo plugin que estarei lançando ainda hoje, o BrCFShops.dll, que libera o uso de itens excellent no seu GameServer 0.97D! ;D

PS2. Não deixem de atualizar seus códigos fontes com a Custom DLL 1.0.0.2 e a BrCFPMS.dll 1.0.0.2 BETA que estarei lançando hoje também! ;D

Até a vista! ;D
Mr.MariN.