Como Implementar Sistema de Referral/Indicação no Servidor de MU
Aprenda a criar um sistema de indicação completo para seu servidor de MU Online, com tabelas SQL, lógica de recompensa e integração ao website.
Visão Geral do Sistema
Um sistema de referral (indicação) recompensa jogadores que trazem novos usuários para o servidor. A implementação envolve três camadas: banco de dados (rastreamento e recompensas), website (geração de links e painel), e opcionalmente integração com o GameServer (concessão de itens ou zen via SQL).
Este tutorial cobre a implementação completa usando SQL Server e PHP, com notas para ASP.NET onde aplicável.
Passo 1: Criar as Tabelas de Controle no SQL Server
Conecte ao SQL Server Management Studio e execute os scripts abaixo no banco MuOnline (ou o nome do seu banco de accounts).
-- Tabela principal de referrals
USE MuOnline;
GO
CREATE TABLE ReferralCodes (
CodeID INT IDENTITY(1,1) PRIMARY KEY,
AccountID VARCHAR(10) NOT NULL,
Code VARCHAR(20) NOT NULL UNIQUE,
CreatedAt DATETIME NOT NULL DEFAULT GETDATE(),
TotalUses INT NOT NULL DEFAULT 0,
MaxUses INT NOT NULL DEFAULT 20,
IsActive BIT NOT NULL DEFAULT 1
);
-- Tabela de registros via indicação
CREATE TABLE ReferralUses (
UseID INT IDENTITY(1,1) PRIMARY KEY,
ReferrerAccount VARCHAR(10) NOT NULL,
ReferredAccount VARCHAR(10) NOT NULL,
UsedAt DATETIME NOT NULL DEFAULT GETDATE(),
ReferredIP VARCHAR(45) NOT NULL,
RewardGranted BIT NOT NULL DEFAULT 0,
RewardGrantedAt DATETIME NULL,
QualifyingLevel INT NOT NULL DEFAULT 0
);
-- Tabela de log de recompensas
CREATE TABLE ReferralRewards (
RewardID INT IDENTITY(1,1) PRIMARY KEY,
AccountID VARCHAR(10) NOT NULL,
RewardType VARCHAR(20) NOT NULL, -- 'ZEN', 'WCOIN', 'ITEM'
RewardValue INT NOT NULL,
GrantedAt DATETIME NOT NULL DEFAULT GETDATE(),
Notes VARCHAR(200) NULL
);
GO
MuOnline_Account), crie essas tabelas no banco de accounts para ter acesso tanto pelo website quanto pelo GameServer.Passo 2: Criar Índices e Stored Procedures
Adicione índices para performance e crie as stored procedures de validação.
-- Índices para consultas frequentes
CREATE INDEX IX_ReferralCodes_AccountID ON ReferralCodes(AccountID);
CREATE INDEX IX_ReferralUses_ReferredAccount ON ReferralUses(ReferredAccount);
CREATE INDEX IX_ReferralUses_ReferrerAccount ON ReferralUses(ReferrerAccount);
GO
-- Procedure: Gerar código único para uma conta
CREATE PROCEDURE sp_ReferralGenerateCode
@AccountID VARCHAR(10)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Code VARCHAR(20);
DECLARE @Exists INT = 1;
-- Verificar se já existe código ativo
IF EXISTS (SELECT 1 FROM ReferralCodes WHERE AccountID = @AccountID AND IsActive = 1)
BEGIN
SELECT Code FROM ReferralCodes WHERE AccountID = @AccountID AND IsActive = 1;
RETURN;
END
-- Gerar código único
WHILE @Exists > 0
BEGIN
SET @Code = UPPER(LEFT(@AccountID, 4)) + LEFT(NEWID(), 8);
SELECT @Exists = COUNT(*) FROM ReferralCodes WHERE Code = @Code;
END
INSERT INTO ReferralCodes (AccountID, Code) VALUES (@AccountID, @Code);
SELECT @Code AS Code;
END
GO
-- Procedure: Registrar uso de código no cadastro
CREATE PROCEDURE sp_ReferralRegisterUse
@Code VARCHAR(20),
@ReferredAccount VARCHAR(10),
@ReferredIP VARCHAR(45)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ReferrerAccount VARCHAR(10);
DECLARE @TotalUses INT;
DECLARE @MaxUses INT;
-- Buscar dados do código
SELECT @ReferrerAccount = AccountID,
@TotalUses = TotalUses,
@MaxUses = MaxUses
FROM ReferralCodes
WHERE Code = @Code AND IsActive = 1;
-- Validações
IF @ReferrerAccount IS NULL
RETURN -1; -- Código inválido
IF @ReferrerAccount = @ReferredAccount
RETURN -2; -- Auto-indicação
IF @TotalUses >= @MaxUses
RETURN -3; -- Limite atingido
IF EXISTS (SELECT 1 FROM ReferralUses WHERE ReferredAccount = @ReferredAccount)
RETURN -4; -- Conta já indicada por outro
-- Verificar IP duplicado (anti-abuse)
IF EXISTS (
SELECT 1 FROM ReferralUses ru
INNER JOIN ReferralCodes rc ON ru.ReferrerAccount = rc.AccountID
WHERE rc.AccountID = @ReferrerAccount AND ru.ReferredIP = @ReferredIP
)
RETURN -5; -- IP já usou indicação deste referrer
-- Registrar indicação
INSERT INTO ReferralUses (ReferrerAccount, ReferredAccount, ReferredIP)
VALUES (@ReferrerAccount, @ReferredAccount, @ReferredIP);
UPDATE ReferralCodes SET TotalUses = TotalUses + 1 WHERE Code = @Code;
RETURN 1; -- Sucesso
END
GO
Passo 3: Procedure de Concessão de Recompensa
-- Procedure: Conceder recompensa quando indicado atingir nível mínimo
CREATE PROCEDURE sp_ReferralGrantReward
@ReferredAccount VARCHAR(10),
@CurrentLevel INT,
@MinLevel INT = 200
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ReferrerAccount VARCHAR(10);
DECLARE @UseID INT;
-- Verificar se existe indicação pendente de recompensa
SELECT @UseID = UseID, @ReferrerAccount = ReferrerAccount
FROM ReferralUses
WHERE ReferredAccount = @ReferredAccount
AND RewardGranted = 0
AND @CurrentLevel >= @MinLevel;
IF @UseID IS NULL RETURN 0;
-- Conceder WCoin ao indicador (ajuste o banco/tabela conforme seu servidor)
UPDATE MEMB_INFO
SET WCoinC = WCoinC + 500
WHERE memb___id = @ReferrerAccount;
-- Conceder bônus ao indicado (opcional)
UPDATE MEMB_INFO
SET WCoinC = WCoinC + 100
WHERE memb___id = @ReferredAccount;
-- Marcar recompensa como concedida
UPDATE ReferralUses
SET RewardGranted = 1,
RewardGrantedAt = GETDATE(),
QualifyingLevel = @CurrentLevel
WHERE UseID = @UseID;
-- Log da recompensa
INSERT INTO ReferralRewards (AccountID, RewardType, RewardValue, Notes)
VALUES (@ReferrerAccount, 'WCOIN', 500, 'Referral: ' + @ReferredAccount);
RETURN 1;
END
GO
MuOnline..items_pdata ou use o sistema de correio do seu servidor (tabela MuOnline..MailItem ou equivalente dependendo da season).Passo 4: Integração com o Website (PHP)
Crie o arquivo referral.php no diretório raiz do seu site (ex: C:/xampp/htdocs/meuservidor/referral.php).
<?php
// referral.php - Sistema de Referral ViciadosMU
// Conexão SQL Server via PDO (ajuste as credenciais)
$dsn = "sqlsrv:Server=localhost;Database=MuOnline";
$user = "sa";
$pass = "SUA_SENHA";
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
session_start();
$account = $_SESSION['account'] ?? null;
if (!$account) { header("Location: login.php"); exit; }
// Gerar ou buscar código do jogador
$stmt = $pdo->prepare("EXEC sp_ReferralGenerateCode ?");
$stmt->execute([$account]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$myCode = $row['Code'] ?? '';
$baseURL = "https://seuservidor.com/register.php?ref=";
$myLink = $baseURL . $myCode;
// Buscar estatísticas
$stmt2 = $pdo->prepare("
SELECT COUNT(*) AS Total,
SUM(CASE WHEN RewardGranted = 1 THEN 1 ELSE 0 END) AS Rewarded
FROM ReferralUses WHERE ReferrerAccount = ?
");
$stmt2->execute([$account]);
$stats = $stmt2->fetch(PDO::FETCH_ASSOC);
?>
<h2>Seu Link de Indicação</h2>
<input type="text" value="<?= htmlspecialchars($myLink) ?>" readonly id="refLink">
<button onclick="navigator.clipboard.writeText(document.getElementById('refLink').value)">
Copiar Link
</button>
<h3>Estatísticas</h3>
<p>Total de indicados: <?= (int)$stats['Total'] ?></p>
<p>Recompensas recebidas: <?= (int)$stats['Rewarded'] ?></p>
Passo 5: Processar Referral no Cadastro
No arquivo de registro (register.php), adicione a chamada à stored procedure após criar a conta:
// Após INSERT bem-sucedido da conta nova:
$refCode = $_GET['ref'] ?? $_POST['ref'] ?? '';
$refCode = preg_replace('/[^A-Z0-9]/', '', strtoupper(trim($refCode)));
$clientIP = $_SERVER['REMOTE_ADDR'];
if (!empty($refCode) && strlen($refCode) <= 20) {
$stmt = $pdo->prepare("DECLARE @ret INT; EXEC @ret = sp_ReferralRegisterUse ?, ?, ?; SELECT @ret AS Result");
$stmt->execute([$refCode, $newAccount, $clientIP]);
$result = $stmt->fetchColumn();
// $result: 1=sucesso, -1=código inválido, -2=auto, -3=limite, -4=já indicado, -5=IP bloqueado
}
Passo 6: Job Automático de Verificação de Nível
Crie um SQL Agent Job para verificar periodicamente os indicados que atingiram o nível mínimo.
-- Script para o SQL Server Agent Job (executar a cada 30 minutos)
USE MuOnline;
GO
DECLARE @Account VARCHAR(10);
DECLARE @Level INT;
DECLARE cur CURSOR FOR
SELECT ru.ReferredAccount, MAX(c.cLevel)
FROM ReferralUses ru
INNER JOIN MuOnline..Character c ON c.AccountID = ru.ReferredAccount
WHERE ru.RewardGranted = 0
GROUP BY ru.ReferredAccount;
OPEN cur;
FETCH NEXT FROM cur INTO @Account, @Level;
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_ReferralGrantReward @Account, @Level, 200;
FETCH NEXT FROM cur INTO @Account, @Level;
END
CLOSE cur;
DEALLOCATE cur;
AccountID na tabela Character pode variar entre versões do MuServer. Em algumas versões S6, use a coluna AccountID diretamente; em outras, pode ser necessário fazer JOIN com MEMB_INFO. Verifique o schema do seu banco antes de executar.Passo 7: Painel Administrativo Básico
Adicione ao seu painel admin a consulta de overview:
-- Relatório de referrals para o admin
SELECT
rc.AccountID AS Indicador,
rc.Code AS Codigo,
rc.TotalUses AS TotalIndicados,
SUM(CASE WHEN ru.RewardGranted = 1 THEN 1 ELSE 0 END) AS Recompensados,
SUM(CASE WHEN ru.RewardGranted = 0 THEN 1 ELSE 0 END) AS Pendentes,
rc.IsActive AS Ativo
FROM ReferralCodes rc
LEFT JOIN ReferralUses ru ON rc.AccountID = ru.ReferrerAccount
GROUP BY rc.AccountID, rc.Code, rc.TotalUses, rc.IsActive
ORDER BY rc.TotalUses DESC;
Troubleshooting
Recompensa não sendo concedida: Verifique se o campo AccountID na tabela Character corresponde exatamente ao valor em MEMB_INFO.memb___id. Diferenças de case (maiúsculas/minúsculas) causam falhas silenciosas no SQL Server com collation case-sensitive.
Código de referral duplicado no NEWID(): O loop WHILE na stored procedure previne isso, mas em servidores com alto volume de cadastros simultâneos adicione um índice UNIQUE na coluna Code (já incluído no script do Passo 1).
IP bloqueando indicações legítimas: Em servidores que usam NAT ou CGNAT (vários jogadores com o mesmo IP público), considere desativar ou suavizar a verificação por IP, ou usar fingerprinting adicional via launcher.
TOP 10 e exiba publicamente os nicknames dos melhores indicadores.Perguntas frequentes
O sistema de referral funciona em qualquer season?
A estrutura SQL e a lógica de rastreamento funcionam em qualquer season (S1 a S13+). A integração com o website depende da sua stack (PHP/ASP.NET), mas as tabelas e stored procedures são compatíveis com SQL Server 2008 ou superior.
Como evitar que um jogador indique a si mesmo criando múltiplas contas?
Registre o IP e o endereço MAC (quando disponível via launcher) no momento do cadastro. Na stored procedure de validação, compare o IP de registro do indicado com o IP do indicador. Bloqueie também indicações entre contas com o mesmo e-mail de recuperação.
Qual o melhor momento para conceder a recompensa ao indicador?
Conceda a recompensa apenas quando o indicado atingir um requisito mínimo de atividade — por exemplo, atingir o nível 200 ou completar 10 resets. Isso evita abusos com contas criadas apenas para acionar o sistema.
Posso limitar o número de indicações por conta?
Sim. Adicione uma coluna ReferralCount na tabela de controle e valide no momento do resgate. Um limite de 10 a 20 indicações ativas por conta é razoável para a maioria dos servidores privados.