Como criar um sistema de indicação (referral) no MU Online
Implemente um sistema de indicação no site do seu servidor de MU Online, com links únicos, recompensas em Cash e proteção contra fraudes de auto-indicação.
Um sistema de indicação — ou referral — transforma seus próprios jogadores no melhor canal de aquisição do servidor. A lógica é simples e poderosa: cada jogador recebe um link único; quando um amigo se cadastra por esse link e realmente começa a jogar, ambos ganham uma recompensa. O resultado é um c
Um sistema de indicação — ou referral — transforma seus próprios jogadores no melhor canal de aquisição do servidor. A lógica é simples e poderosa: cada jogador recebe um link único; quando um amigo se cadastra por esse link e realmente começa a jogar, ambos ganham uma recompensa. O resultado é um crescimento orgânico e barato, movido por quem já confia no servidor. Mas há um abismo entre a ideia e uma implementação que não seja imediatamente explorada por quem quer farmar recompensas com contas falsas. Este tutorial mostra como construir um sistema de referral no site do seu servidor de MU Online que seja ao mesmo tempo atraente para o jogador honesto e resistente à fraude, com links rastreáveis, liberação condicionada a engajamento real e crédito automático de Cash. Usaremos PHP e SQL Server como exemplo por serem o padrão da maioria dos servidores privados, mas a lógica se aplica a qualquer stack. Nomes de tabelas e colunas variam por versão e emulador, então trate cada query como esqueleto a adaptar.
Pré-requisitos
O sistema de indicação vive no site, então você precisa de um site funcional integrado ao banco do servidor. Se ainda não integrou site e jogo, comece pelo guia de como criar servidor de MU Online antes de seguir.
- Site do servidor rodando em PHP 7.4+ com acesso ao banco de dados.
- SQL Server com a tabela de contas do MU (frequentemente
MEMB_INFO) acessível. - Sistema de contas/login já funcionando no site.
- Uma coluna ou tabela onde o Cash (moeda do cash shop) do jogador é armazenado — o nome varia por versão (ex.:
CashShopData,WCoinC,Credits). - Conhecimento básico de PHP, SQL e sessões de login.
Como o fluxo de indicação funciona
Antes do código, fixe o fluxo. Cada etapa existe para fechar uma brecha de fraude:
- O jogador logado acessa a página "Indique um amigo" e vê seu código de indicação único e o link pronto para copiar.
- Um novo visitante clica no link; o código fica gravado na sessão/cookie dele.
- Ao se cadastrar, a nova conta é vinculada ao indicador, com status pendente.
- O sistema monitora o progresso do indicado. Quando ele atinge uma meta real (ex.: nível 150 ou 3 dias jogados), o status vira liberado.
- Só então as recompensas são creditadas para os dois lados, e o vínculo é marcado como pago para nunca pagar duas vezes.
O ponto crítico é o passo 4: recompensa liberada no cadastro é convite à fraude. Recompensa liberada por engajamento real filtra 90% dos abusos.
Passo 1 — Estrutura de dados
Crie uma tabela dedicada para os referrals. Ela mantém o histórico auditável e separa a lógica de indicação das tabelas do jogo:
CREATE TABLE Referrals (
Id INT IDENTITY(1,1) PRIMARY KEY,
ReferrerAcc VARCHAR(20) NOT NULL, -- conta que indicou
ReferredAcc VARCHAR(20) NOT NULL, -- conta indicada
ReferredIP VARCHAR(45) NULL,
Status VARCHAR(10) NOT NULL DEFAULT 'pendente', -- pendente/liberado/pago
CreatedAt DATETIME NOT NULL DEFAULT GETDATE(),
RewardedAt DATETIME NULL,
CONSTRAINT UQ_Referred UNIQUE (ReferredAcc) -- cada conta só é indicada uma vez
);
Gere o código de indicação a partir do próprio nome da conta (com um hash curto) ou armazene um código aleatório por conta. Para simplicidade, muitos servidores usam o próprio nome de usuário como código.
Passo 2 — Capturar o código na chegada
Quando alguém acessa o site com ?ref=CODIGO, grave esse código antes que ele se perca. Um cookie de longa duração cobre visitantes que não se cadastram na mesma sessão:
<?php
// incluir no topo do index.php do site
if (isset($_GET['ref']) && !isset($_COOKIE['ref_code'])) {
$ref = preg_replace('/[^a-zA-Z0-9_]/', '', $_GET['ref']);
if ($ref !== '') {
// 30 dias de janela de atribuição
setcookie('ref_code', $ref, time() + 60*60*24*30, '/');
}
}
Note a sanitização: aceitamos apenas caracteres válidos de conta, o que já elimina tentativas de injeção pela URL.
Passo 3 — Vincular no cadastro
No processamento do cadastro, depois de criar a conta com sucesso, registre o vínculo — mas somente após as checagens antifraude:
<?php
function registrarReferral(PDO $db, string $novaConta, string $novoIP): void {
if (empty($_COOKIE['ref_code'])) return;
$ref = preg_replace('/[^a-zA-Z0-9_]/', '', $_COOKIE['ref_code']);
if ($ref === '' || strcasecmp($ref, $novaConta) === 0) return; // auto-indicação
// O indicador precisa existir de fato
$stmt = $db->prepare("SELECT memb___id FROM MEMB_INFO WHERE memb___id = ?");
$stmt->execute([$ref]);
if (!$stmt->fetch()) return;
// Bloqueia mesmo IP entre indicador e indicado
$ipInd = $db->prepare("
SELECT r.ReferredIP FROM Referrals r
WHERE r.ReferrerAcc = ? AND r.ReferredIP = ?");
$ipInd->execute([$ref, $novoIP]);
if ($ipInd->fetch()) return; // já indicou alguém deste mesmo IP
$ins = $db->prepare("
INSERT INTO Referrals (ReferrerAcc, ReferredAcc, ReferredIP)
VALUES (?, ?, ?)");
$ins->execute([$ref, $novaConta, $novoIP]);
}
Passo 4 — Liberar a recompensa por engajamento
Este é o coração antifraude. Um script agendado (cron ou Agendador de Tarefas do Windows) roda periodicamente, verifica quais indicados atingiram a meta e libera as recompensas. A meta de exemplo é nível 150 em algum personagem da conta — ajuste o nome da tabela Character e a coluna de nível à sua versão:
<?php
// cron/liberar_referrals.php — rodar a cada 10 min
require 'db.php';
$pendentes = $db->query("
SELECT Id, ReferrerAcc, ReferredAcc
FROM Referrals WHERE Status = 'pendente'")->fetchAll(PDO::FETCH_ASSOC);
foreach ($pendentes as $r) {
// O indicado alcançou a meta?
$chk = $db->prepare("
SELECT TOP 1 cLevel FROM Character
WHERE AccountID = ? AND cLevel >= 150");
$chk->execute([$r['ReferredAcc']]);
if ($chk->fetch()) {
creditarCash($db, $r['ReferrerAcc'], 200); // indicador
creditarCash($db, $r['ReferredAcc'], 100); // indicado
$up = $db->prepare("
UPDATE Referrals SET Status = 'pago', RewardedAt = GETDATE()
WHERE Id = ?");
$up->execute([$r['Id']]);
}
}
function creditarCash(PDO $db, string $conta, int $valor): void {
// Nome da coluna/tabela de Cash VARIA por versão
$up = $db->prepare("
UPDATE MEMB_INFO SET Credits = Credits + ? WHERE memb___id = ?");
$up->execute([$valor, $conta]);
}
Repare que a recompensa só é creditada uma vez, porque o status vira pago na mesma transação lógica.
Passo 5 — Página do jogador
Dê ao jogador logado uma página que mostra o link e o histórico. É o que gera compartilhamento:
<?php
$conta = $_SESSION['username'];
$link = "https://seusite.com/?ref=" . urlencode($conta);
$stats = $db->prepare("
SELECT
SUM(CASE WHEN Status = 'pago' THEN 1 ELSE 0 END) AS pagos,
COUNT(*) AS total
FROM Referrals WHERE ReferrerAcc = ?");
$stats->execute([$conta]);
$row = $stats->fetch(PDO::FETCH_ASSOC);
?>
<h2>Indique e ganhe</h2>
<input type="text" value="<?= htmlspecialchars($link) ?>" readonly onclick="this.select()">
<p>Amigos que já jogaram: <?= (int)$row['pagos'] ?> de <?= (int)$row['total'] ?> indicados</p>
Camadas de proteção antifraude
Nenhuma checagem isolada resolve. Combine várias e o custo de fraudar supera a recompensa:
| Camada | O que verifica | Limite |
|---|---|---|
| Meta de engajamento | Nível/tempo mínimo do indicado | Filtra contas descartáveis |
| Bloqueio de auto-indicação | Nome de conta igual | Impede o caso mais óbvio |
| Comparação de IP | Mesmo IP entre as contas | IP dinâmico e VPN driblam |
| HWID/hardware | Mesma máquina (quando disponível) | Depende de suporte do cliente |
| E-mail único | Mesmo e-mail nas duas contas | Só se e-mail for obrigatório |
| Limite por indicador | Máximo de indicações por dia | Reduz farm em massa |
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Recompensa dada em massa a contas fantasma | Liberação no cadastro | Condicione à meta de engajamento no cron |
| Mesmo jogador ganha várias vezes pelo mesmo indicado | Falta de status "pago" | Use a constraint única e marque como pago ao creditar |
| Cash não é creditado | Nome da coluna errado | Confira o schema; a coluna de Cash varia por versão |
Código ?ref= some antes do cadastro | Sem cookie de atribuição | Grave o código em cookie de 30 dias |
| Auto-indicação passa | Só compara nome | Combine IP, HWID e e-mail além do nome |
| Cron não roda no Windows | Sem tarefa agendada | Crie tarefa no Agendador para chamar o PHP via CLI |
Boas práticas
Use sempre prepared statements — o exemplo acima nunca concatena entrada do usuário em SQL. Registre logs de cada liberação de recompensa para auditar disputas. Defina recompensas modestas o suficiente para não quebrar a economia do servidor, mas atraentes o bastante para motivar o compartilhamento; Cash é preferível a itens porque é trivial de creditar e reverter. E comunique as regras claramente na página de indicação: metas, prazos e o que caracteriza fraude passível de banimento.
Checklist de lançamento
- Tabela
Referralscriada com constraint de indicado único - Captura do código
?ref=via cookie de 30 dias - Vínculo criado no cadastro somente após checagens antifraude
- Bloqueio de auto-indicação por nome, IP e e-mail
- Cron/tarefa liberando recompensas por meta de engajamento
- Crédito de Cash testado com o schema real do servidor
- Página do jogador com link e histórico funcionando
- Todas as queries usando prepared statements
- Regras publicadas e recompensas balanceadas com a economia
- Logs de liberação ativos para auditoria
Perguntas frequentes
Quando devo liberar a recompensa da indicação?
Nunca no cadastro. Libere só quando o indicado atingir uma meta real de engajamento, como um nível mínimo ou um tempo mínimo jogado, para evitar contas falsas criadas apenas pela recompensa.
Como impedir que a pessoa se auto-indique?
Compare IP, hardware/HWID quando disponível e e-mail entre indicador e indicado, e bloqueie recompensas quando coincidirem. Nenhuma checagem isolada é perfeita; combine várias.
Onde guardo o código de indicação?
Em uma coluna na tabela de contas ou em uma tabela própria de referrals. O ideal é uma tabela dedicada que registra indicador, indicado, status e data, mantendo o histórico auditável.
Posso dar recompensa em itens em vez de Cash?
Sim, mas Cash (moeda do cash shop) é mais simples e seguro de creditar via site. Entregar itens exige manipular o inventário no banco, o que é mais arriscado e varia muito por versão.
O sistema de referral funciona em qualquer versão de MU?
A lógica do site é independente da versão. O que muda é o nome das tabelas de conta e a forma de creditar Cash, que variam por emulador; adapte as queries ao seu schema.