https://github.com/ocalasans/samp-rich-presence
samp-rich-presence is an ASI mod for SA-MP (San Andreas Multiplayer), developed in C++, that integrates Discord Rich Presence to display server information.
https://github.com/ocalasans/samp-rich-presence
asi cpp discord dll gta gtasa mod rich-presence sa-mp sa-mp-development samp
Last synced: about 2 months ago
JSON representation
samp-rich-presence is an ASI mod for SA-MP (San Andreas Multiplayer), developed in C++, that integrates Discord Rich Presence to display server information.
- Host: GitHub
- URL: https://github.com/ocalasans/samp-rich-presence
- Owner: ocalasans
- License: apache-2.0
- Created: 2025-01-12T20:46:46.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2025-02-08T14:06:18.000Z (3 months ago)
- Last Synced: 2025-02-08T14:23:38.204Z (3 months ago)
- Topics: asi, cpp, discord, dll, gta, gtasa, mod, rich-presence, sa-mp, sa-mp-development, samp
- Language: C++
- Homepage:
- Size: 322 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SA-MP Rich Presence
O SA-MP Rich Presence é um ASI para SA-MP (San Andreas Multiplayer) que atualiza automaticamente seu status do Discord com informações detalhadas do servidor. O ASI é injetado no jogo quando você se conecta a um servidor SA-MP, exibindo informações do servidor.
## Idiomas
- Deutsch: [README](translations/Deutsch/README.md)
- English: [README](translations/English/README.md)
- Español: [README](translations/Espanol/README.md)
- Français: [README](translations/Francais/README.md)
- Italiano: [README](translations/Italiano/README.md)
- Polski: [README](translations/Polski/README.md)
- Русский: [README](translations/Русский/README.md)
- Svenska: [README](translations/Svenska/README.md)
- Türkçe: [README](translations/Turkce/README.md)## Índice
- [SA-MP Rich Presence](#sa-mp-rich-presence)
- [Idiomas](#idiomas)
- [Índice](#índice)
- [O que é um ASI?](#o-que-é-um-asi)
- [Funcionalidades](#funcionalidades)
- [Discord Rich Presence](#discord-rich-presence)
- [Requisitos](#requisitos)
- [Instalação](#instalação)
- [Arquitetura Técnica Detalhada](#arquitetura-técnica-detalhada)
- [Sistema Principal (main.cpp)](#sistema-principal-maincpp)
- [Gerenciador do Discord (discord\_manager.cpp)](#gerenciador-do-discord-discord_managercpp)
- [Gerenciador de Servidor (server\_manager.cpp)](#gerenciador-de-servidor-server_managercpp)
- [Sistema de Rede (network\_manager.cpp)](#sistema-de-rede-network_managercpp)
- [Consulta ao Servidor (server\_query.cpp)](#consulta-ao-servidor-server_querycpp)
- [Integração com a SPC](#integração-com-a-spc)
- [O que é o SPC Integration?](#o-que-é-o-spc-integration)
- [Como Funciona](#como-funciona)
- [Gerenciador de URL (url\_manager.cpp)](#gerenciador-de-url-url_managercpp)
- [Para Desenvolvedores de Servidor](#para-desenvolvedores-de-servidor)
- [Estrutura do Código](#estrutura-do-código)
- [Constantes Globais (constants.h)](#constantes-globais-constantsh)
- [Estruturas de Dados (server\_types.h)](#estruturas-de-dados-server_typesh)
- [Tratamento de Erros](#tratamento-de-erros)
- [Sistema de Processamento de Linha de Comando](#sistema-de-processamento-de-linha-de-comando)
- [Parser de Linha de Comando (command\_line\_parser.cpp)](#parser-de-linha-de-comando-command_line_parsercpp)
- [Protocolo de Comunicação SA-MP](#protocolo-de-comunicação-sa-mp)
- [Implementação do Protocolo](#implementação-do-protocolo)
- [Benefícios do SA-MP Rich Presence](#benefícios-do-sa-mp-rich-presence)
- [Notas Técnicas Adicionais](#notas-técnicas-adicionais)
- [Licença](#licença)
- [Condições:](#condições)## O que é um ASI?
ASI é uma biblioteca dinâmica (.dll) renomeada com a extensão .asi que é automaticamente carregada por um loader ASI quando o GTA San Andreas é iniciado. Os plugins ASI permitem modificar ou adicionar funcionalidades ao jogo sem alterar os arquivos originais, sendo uma das formas mais populares de modding para o GTA San Andreas e outros jogos da série GTA. Com um ASI loader instalado, você pode facilmente instalar ou remover modificações simplesmente adicionando ou removendo arquivos .asi da pasta do jogo.
## Funcionalidades
### Discord Rich Presence
O Discord Rich Presence é uma funcionalidade que permite que aplicativos mostrem informações detalhadas sobre o que o usuário está fazendo diretamente no perfil do Discord. No caso do SA-MP Rich Presence, as seguintes informações são exibidas:
- Nome do servidor (Hostname).
- Nome do jogador.
- Número atual de jogadores e máximo de jogadores.
- IP e porta do servidor.
- Imagem personalizada do servidor (requer que o servidor tenha o plugin [SPC Integration](https://github.com/spc-samp/spc-integration)).
- Tempo de jogo.
- Status da conexão.## Requisitos
- Cliente SA-MP (se não tiver: [clients-samp](https://github.com/spc-samp/clients-samp)).
- Aplicativo Discord Desktop.
- Sistema Operacional Windows.
- Visual C++ Runtime.
- ASI Loader instalado no GTA San Andreas.## Instalação
1. Baixe a versão mais recente do ASI compilado em [releases](https://github.com/ocalasans/samp-rich-presence/releases).
2. Certifique-se de ter um ASI Loader instalado no seu GTA San Andreas.
3. Copie o arquivo .asi baixado para a pasta do seu GTA San Andreas.
4. Inicie o jogo com o SA-MP.
5. O ASI será automaticamente inicializado quando você entrar em um servidor.## Arquitetura Técnica Detalhada
### Sistema Principal (main.cpp)
O arquivo main.cpp é o ponto de entrada do ASI e responsável por:
1. Inicialização do sistema:
```cpp
BOOL APIENTRY DllMain(HMODULE module_handle, DWORD reason, LPVOID) {
switch (reason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(module_handle);
CreateThread(nullptr, 0, Update_Thread, nullptr, 0, nullptr);
break;
// ...
}return TRUE;
}
```2. Gerenciamento da thread de atualização:
```cpp
DWORD WINAPI Update_Thread(LPVOID) {
// Inicializa WSA para operações de rede
WSAData wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0)
return 1;
// Processa parâmetros de linha de comando
std::string server_ip, player_name;
int server_port;
// Inicializa gerenciadores
Global_Server_Manager = std::make_unique(server_ip, server_port, player_name);
Global_Discord_Manager = std::make_unique();
// Loop principal de atualização
while (true) {
Global_Server_Manager->Update();
Global_Discord_Manager->Update_Presence(...);
Sleep(Constants::PRESENCE_UPDATE_INTERVAL);
}
}
```### Gerenciador do Discord (discord_manager.cpp)
O Discord_Manager é responsável por toda a integração com o Discord Rich Presence:
1. Inicialização do Discord RPC:
```cpp
void Discord_Manager::Initialize() noexcept {
Sleep(5000); // Aguarda inicialização do Discord
DiscordEventHandlers discord_handlers{};
Discord_Initialize("DISCORD_APP_ID", &discord_handlers, 1, NULL); // "DISCORD_APP_ID > Application ID"
start_timestamp = time(nullptr); // Marca o início da sessão
}
```2. Atualização da presença:
```cpp
void Discord_Manager::Update_Presence(const Server_Information& server_info, std::string_view player_name, std::string_view current_image, bool is_connected) noexcept {
DiscordRichPresence discord_presence{};
// Configura informações básicas
discord_presence.state = player_name.data();
discord_presence.details = server_info.Hostname.c_str();
discord_presence.largeImageKey = current_image.data();
// Adiciona informações do servidor
discord_presence.largeImageText = server_info.Server_Address.c_str();
discord_presence.startTimestamp = start_timestamp;
discord_presence.partySize = server_info.Players;
discord_presence.partyMax = server_info.Max_Players;
Discord_UpdatePresence(&discord_presence);
}
```### Gerenciador de Servidor (server_manager.cpp)
O Server_Manager coordena todas as operações relacionadas ao servidor:
1. Gerenciamento de estado:
```cpp
Server_Manager::Server_Manager(const std::string& ip, int port, const std::string& name)
: connection_status(false)
, server_ip(ip)
, server_port(port)
, player_name(name)
, current_image_url(Constants::DEFAULT_IMAGE)
{}
```2. Atualização de informações:
```cpp
bool Server_Manager::Update() {
bool query_success = server_query.Query(server_data);
if (query_success) {
connection_status = true;
server_data.Server_Address = Get_Server_Address();
// Tenta obter imagem personalizada do servidor
std::string new_image_url = url_manager.Get_Image_URL(server_data.Server_Address);if (!new_image_url.empty())
current_image_url = new_image_url;
}
// ...
}
```### Sistema de Rede (network_manager.cpp)
O Network_Manager implementa toda a comunicação de rede:
1. Inicialização do socket:
```cpp
bool Network_Manager::Initialize(std::string_view ip, int port) noexcept {
network_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Configura timeout
timeval Socket_Timeout{ 0, Constants::QUERY_TIMEOUT };
setsockopt(network_socket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&Socket_Timeout), sizeof(Socket_Timeout));
// Configura endereço do servidor
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
inet_pton(AF_INET, ip.data(), &server_address.sin_addr);
return true;
}
```### Consulta ao Servidor (server_query.cpp)
O Server_Query implementa o protocolo de consulta do SA-MP:
1. Montagem do pacote de consulta:
```cpp
bool Server_Query::Assemble_Query_Packet(char* packet) noexcept {
memcpy(packet, QUERY_SIGNATURE, 4); // "SAMP"
packet[10] = 'i'; // Information queryreturn true;
}
```2. Processamento da resposta:
```cpp
bool Server_Query::Parse_Response(char* response_buffer, int received_bytes, Server_Information& server_data) noexcept {
// Extrai informações como:
// - Número de jogadores
// - Máximo de jogadores
// - Hostname
}
```## Integração com a SPC
### O que é o SPC Integration?
[SPC Integration](https://github.com/spc-samp/spc-integration) é um plugin desenvolvido para **SA-MP** (San Andreas Multiplayer) e **open.mp** (Open Multiplayer) que atua como uma ponte entre servidores e o ecossistema da **SPC**. O plugin coleta informações cruciais do servidor, incluindo:
- IP e porta.
- URL do site do servidor.
- URL da imagem personalizada.
- Informações de configuração.Essas informações são enviadas e armazenadas de forma segura no armazenador de dados da **SPC (SA-MP Programming Community)**, permitindo uma integração com várias aplicações da **SPC**, incluindo o Rich Presence.
### Como Funciona
1. O servidor utiliza o plugin [SPC Integration](https://github.com/spc-samp/spc-integration) para registrar sua imagem personalizada.
2. A imagem é armazenada no armazenamento de dados da **SPC** dentro do arquivo JSON do servidor.
3. Quando um jogador conecta no servidor:
- O URL_Manager do ASI tenta buscar o arquivo JSON do servidor (formato: `ip-port.json`).
- Se encontrado, extrai a URL da imagem do parâmetro `spc_integration_image`.
- A imagem é então exibida no Discord Rich Presence do jogador.### Gerenciador de URL (url_manager.cpp)
O URL_Manager é responsável por toda a comunicação com o armazenamento de dados da **SPC**:
1. Busca da imagem do servidor:
```cpp
std::string URL_Manager::Get_Image_URL(const std::string& server_address) {
std::string formatted_address = server_address;
// Converte ":" para "-" no endereço
size_t colon_pos = formatted_address.find(':');if (colon_pos != std::string::npos)
formatted_address.replace(colon_pos, 1, "-");
// Busca JSON do servidor
std::string image_url;if (!Get_URL_From_File(formatted_address, image_url))
return Constants::DEFAULT_IMAGE;
return image_url;
}
```2. Processamento do JSON:
```cpp
std::string URL_Manager::Parse_JSON(const std::string& json_content) {
const std::string key = "\"spc_integration_image\":";
size_t key_pos = json_content.find(key);
// Extrai URL da imagem do JSON
// ...
return image_url;
}
```## Para Desenvolvedores de Servidor
Se você é um desenvolvedor de servidor SA-MP, recomendamos fortemente a instalação do plugin [SPC Integration](https://github.com/spc-samp/spc-integration) pelos seguintes motivos:
1. Visibilidade:
- A imagem personalizada do seu servidor será exibida no Discord de todos os jogadores que usam este ASI.
- Aumenta o reconhecimento da marca do seu servidor.
- Proporciona uma apresentação mais profissional.2. Benefícios:
- Maior engajamento dos jogadores.
- Diferenciação visual no Discord.
- Integração automática com o Rich Presence.3. Como implementar:
- Leia o repositório do plugin [SPC Integration](https://github.com/spc-samp/spc-integration) para saber como implementar.## Estrutura do Código
O projeto é organizado em vários componentes:
```
src/
├── discord/ # Biblioteca Discord RPC
├── command_line_parser.* # Processamento de argumentos
├── constants.h # Constantes globais
├── discord_manager.* # Integração com Discord
├── main.cpp # Ponto de entrada
├── network_manager.* # Operações de rede
├── server_manager.* # Gerenciamento do servidor
├── server_query.* # Protocolo SA-MP
├── server_types.h # Estruturas de dados
└── url_manager.* # Integração com SPC
```### Constantes Globais (constants.h)
O arquivo define várias constantes importantes:
```cpp
namespace Constants {
// Valores padrão
inline constexpr char DEFAULT_SERVER_IP[] = "127.0.0.1";
inline constexpr int DEFAULT_SERVER_PORT = 7777;
// Configurações de rede
inline constexpr int QUERY_TIMEOUT = 1000;
inline constexpr int QUERY_PACKET_SIZE = 11;
inline constexpr int QUERY_BUFFER_SIZE = 512;
// Configurações de retry
inline constexpr int MAX_RETRY_ATTEMPTS = 3;
// Intervalos
inline constexpr int PRESENCE_UPDATE_INTERVAL = 5000;
}
```### Estruturas de Dados (server_types.h)
Define as estruturas principais:
```cpp
struct Server_Information {
uint16_t Players{ 0 }; // Jogadores online
uint16_t Max_Players{ 0 }; // Máximo de jogadores
std::string Hostname; // Nome do servidor
std::string Server_Image; // URL da imagem
std::string Server_Address; // Endereço do servidor
};
```## Tratamento de Erros
O sistema implementa um robusto sistema de tratamento de erros:
1. Timeout de rede:
```cpp
timeval Socket_Timeout{ 0, Constants::QUERY_TIMEOUT };
setsockopt(network_socket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&Socket_Timeout), sizeof(Socket_Timeout));
```2. Sistema de retry:
```cpp
bool Server_Query::Try_Query(Server_Information& server_data, int retry_count) noexcept {
for (int attempt = 0; attempt <= retry_count; attempt++) {
if (network_manager.Send_Query(...))
return true;
// Aguarda antes de tentar novamente
std::this_thread::sleep_for(std::chrono::milliseconds(100 * (attempt + 1)));
}return false;
}
```3. Fallback para imagem padrão:
```cpp
std::string URL_Manager::Get_Image_URL(const std::string& server_address) {
// Se algo der errado, retorna a imagem padrão
if (!session_handle)
return Constants::DEFAULT_IMAGE;std::string image_url;
if (!Get_URL_From_File(formatted_address, image_url))
return Constants::DEFAULT_IMAGE;return image_url;
}
```4. Monitoramento de estado de conexão:
```cpp
bool Server_Manager::Update() {
auto current_time = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast(current_time - last_successful_query);
// Se ficar mais de 15 segundos sem resposta, considera desconectado
if (duration.count() > 15) {
connection_status = false;
current_image_url = Constants::DEFAULT_IMAGE;
}
}
```## Sistema de Processamento de Linha de Comando
O ASI implementa um sistema flexível para processar argumentos de linha de comando:
### Parser de Linha de Comando (command_line_parser.cpp)
1. Processamento principal:
```cpp
bool Command_Line_Parser::Parse(const wchar_t* command_line, std::string& server_ip, int& server_port, std::string& player_name) {
// Define valores padrão
server_ip = Constants::DEFAULT_SERVER_IP;
server_port = Constants::DEFAULT_SERVER_PORT;// Processa cada parâmetro
std::wstring ip_parameter = Parse_Parameter(command_string, L"-h");
std::wstring port_parameter = Parse_Parameter(command_string, L"-p");
std::wstring name_parameter = Parse_Parameter(command_string, L"-n");// Converte e valida os valores
if (!ip_parameter.empty())
server_ip = Convert_To_String(ip_parameter);if (!port_parameter.empty())
server_port = std::stoi(port_parameter);if (!name_parameter.empty())
player_name = Convert_To_String(name_parameter);// Verifica se todos os parâmetros necessários estão presentes
return !server_ip.empty() && server_port > 0 && !player_name.empty();
}
```2. Extração de parâmetros:
```cpp
std::wstring Command_Line_Parser::Parse_Parameter(const std::wstring& command_string, const wchar_t* parameter) {
size_t position = command_string.find(parameter);
if (position != std::wstring::npos) {
position += wcslen(parameter) + 1;
size_t end_position = command_string.find(L" ", position);
if (end_position == std::wstring::npos)
end_position = command_string.length();
return command_string.substr(position, end_position - position);
}
return L"";
}
```## Protocolo de Comunicação SA-MP
O ASI implementa o protocolo de consulta do SA-MP para obter informações do servidor:
1. Estrutura do pacote de consulta:
- 4 bytes: Assinatura "SAMP"
- 7 bytes: Dados adicionais
- Último byte: 'i' (indica consulta de informações)2. Estrutura da resposta:
- Cabeçalho do pacote
- Players (uint16_t)
- Max_Players (uint16_t)
- Hostname (string)### Implementação do Protocolo
```cpp
bool Server_Query::Parse_Response(char* response_buffer, int received_bytes, Server_Information& server_data) noexcept {
char* current_pos = response_buffer + Constants::QUERY_PACKET_SIZE;
const char* buffer_end = response_buffer + received_bytes;// Pular "password"
current_pos += sizeof(bool);
// Lê dados fixos
memcpy(&server_data.Players, current_pos, sizeof(server_data.Players));
current_pos += sizeof(server_data.Players);
memcpy(&server_data.Max_Players, current_pos, sizeof(server_data.Max_Players));
current_pos += sizeof(server_data.Max_Players);// Lê Hostname e pula "gamemode" e "language"
auto read_string = [](char*& pos, const char* end, std::string& str) noexcept -> bool {
uint32_t length;
memcpy(&length, pos, sizeof(length));
pos += sizeof(length);
str.assign(pos, length);
pos += length;
return true;
};if (!read_string(current_pos, buffer_end, server_data.Hostname))
return false;
// Pular "gamemode" e "language"
// ...return true;
}
```## Benefícios do SA-MP Rich Presence
1. Para Jogadores:
- Visualização rápida do servidor atual.
- Informações detalhadas sobre o servidor.
- Integração perfeita com o Discord.
- Experiência de jogo mais social.2. Para Servidores:
- Maior visibilidade através do Discord.
- Marketing orgânico através dos jogadores.
- Identidade visual personalizada (com o plugin [SPC Integration](https://github.com/spc-samp/spc-integration)).
- Estatísticas em tempo real.## Notas Técnicas Adicionais
1. Thread Safety:
- O ASI utiliza um único thread para atualizações.
- Gerenciadores são thread-safe por design.
- Recursos são propriamente sincronizados.2. Uso de Memória:
- Alocação mínima de memória.
- Buffers pré-alocados para queries.
- Gerenciamento automático de recursos (RAII).3. Performance:
- Queries otimizadas com timeout.
- Sistema de retry inteligente.
- Intervalo de atualização configurável.4. Compatibilidade:
- Suporte a Unicode.
- Compatível com Windows moderno.
- Suporte a IPv4.## Licença
Este ASI está protegido sob a Licença Apache 2.0, que permite:
- ✔️ Uso comercial e privado
- ✔️ Modificação do código fonte
- ✔️ Distribuição do código
- ✔️ Concessão de patentes### Condições:
- Manter o aviso de direitos autorais
- Documentar alterações significativas
- Incluir cópia da licença Apache 2.0Para mais detalhes sobre a licença: http://www.apache.org/licenses/LICENSE-2.0
**Copyright (c) Calasans - Todos os direitos reservados**