O maior portal de MU Online do Brasil — desde 2003
Tutorial Avançado Tutoriais

Como Implementar Sistema de Ranking Automático no Website do MU

Aprenda a criar um sistema de ranking automático integrado ao banco de dados do seu servidor MU Online, com atualização em tempo real via SQL e PHP.

EQ Equipe ViciadosMU · Atualizado em 3 jul 2026 · ⏱ 12 min de leitura

Exibir um ranking atualizado automaticamente é um dos recursos mais valorizados pelos jogadores de servidores MU Online. Este guia explica como integrar o banco de dados SQL Server do seu servidor MuServer (Season 6 em diante) com um website PHP para gerar rankings de personagens, resets e castles — sem intervenção manual.

Pré-requisitos

Antes de começar, confirme que você possui:

  • Acesso ao SQL Server Management Studio (SSMS) com permissão de leitura/escrita no banco MuOnline
  • PHP 7.4+ com extensão sqlsrv ou pdo_sqlsrv instalada (XAMPP ou AppServ no Windows Server)
  • Acesso ao SQL Server Agent para agendar Jobs
  • Permissão para criar tabelas e stored procedures no banco de dados
Nota: Este tutorial usa o banco de dados padrão MuOnline do MuServer Season 6. Versões anteriores (S2/S3) usam estruturas de tabela ligeiramente diferentes — adapte os nomes de colunas conforme necessário consultando sua tabela Character.

Passo 1: Entender a Estrutura das Tabelas Relevantes

O MuServer armazena os dados de personagem na tabela Character dentro do banco MuOnline. As colunas mais usadas para ranking são:

-- Verificar estrutura da tabela Character
USE MuOnline;
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Character'
ORDER BY ORDINAL_POSITION;

Colunas essenciais para ranking:

ColunaDescrição
NameNome do personagem
AccountIDConta vinculada
cLevelLevel atual
ClassClasse do personagem (byte)
ResetsNúmero de resets (se configurado)
PkCountContagem de PK
MoneyZen do personagem
MapNumberMapa atual (para verificar se está online)

Passo 2: Criar a Tabela de Cache de Ranking

Em vez de consultar a tabela Character diretamente a cada requisição do website, crie uma tabela de cache dedicada. Isso evita lentidão no banco de dados durante picos de acesso.

USE MuOnline;
GO

CREATE TABLE RankingCache (
    RankPosition     INT IDENTITY(1,1) PRIMARY KEY,
    CharacterName    VARCHAR(10)  NOT NULL,
    AccountID        VARCHAR(10)  NOT NULL,
    CharClass        TINYINT      NOT NULL,
    CharLevel        SMALLINT     NOT NULL,
    CharResets       INT          NOT NULL DEFAULT 0,
    CharZen          BIGINT       NOT NULL DEFAULT 0,
    GuildName        VARCHAR(8)   NULL,
    LastUpdate       DATETIME     NOT NULL DEFAULT GETDATE(),
    RankType         VARCHAR(20)  NOT NULL DEFAULT 'level'
);

CREATE INDEX IX_RankingCache_Type ON RankingCache (RankType, RankPosition);
GO

Passo 3: Criar a Stored Procedure de Atualização

A stored procedure abaixo apaga e recria os dados de cache para cada tipo de ranking. Execute-a no SSMS para criá-la:

USE MuOnline;
GO

CREATE PROCEDURE sp_UpdateRankingCache
AS
BEGIN
    SET NOCOUNT ON;

    -- Limpar cache anterior
    DELETE FROM RankingCache;

    -- Ranking por Level e Resets
    INSERT INTO RankingCache (CharacterName, AccountID, CharClass, CharLevel, CharResets, CharZen, GuildName, RankType)
    SELECT TOP 200
        C.Name,
        C.AccountID,
        C.Class,
        C.cLevel,
        ISNULL(C.Resets, 0),
        C.Money,
        G.G_Name,
        'level'
    FROM Character C
    LEFT JOIN GuildMember GM ON GM.Name = C.Name
    LEFT JOIN Guild G ON G.G_Name = GM.G_Name
    WHERE C.cLevel > 0
      AND C.AccountID NOT IN (
          SELECT memb___id FROM MEMB_INFO WHERE memb_stat = 1
      )
    ORDER BY ISNULL(C.Resets, 0) DESC, C.cLevel DESC, C.Money DESC;

    -- Ranking por Zen (riqueza)
    INSERT INTO RankingCache (CharacterName, AccountID, CharClass, CharLevel, CharResets, CharZen, GuildName, RankType)
    SELECT TOP 100
        C.Name,
        C.AccountID,
        C.Class,
        C.cLevel,
        ISNULL(C.Resets, 0),
        C.Money,
        G.G_Name,
        'zen'
    FROM Character C
    LEFT JOIN GuildMember GM ON GM.Name = C.Name
    LEFT JOIN Guild G ON G.G_Name = GM.G_Name
    WHERE C.cLevel > 0
      AND C.AccountID NOT IN (
          SELECT memb___id FROM MEMB_INFO WHERE memb_stat = 1
      )
    ORDER BY C.Money DESC;

    -- Atualizar timestamp
    UPDATE RankingCache SET LastUpdate = GETDATE();

    PRINT 'RankingCache atualizado com sucesso.';
END;
GO
Dica: Adicione memb_stat = 1 na exclusão para filtrar contas de GM. Se seu servidor usar uma coluna diferente para marcar administradores, ajuste o filtro conforme a estrutura do seu MEMB_INFO.

Passo 4: Agendar Atualização Automática via SQL Server Agent

Crie um Job no SQL Server Agent para executar a procedure automaticamente a cada 10 minutos:

  1. Abra o SSMS → expanda SQL Server Agent → clique com o botão direito em JobsNew Job
  2. General tab: Name = Atualizar Ranking MU
  3. Steps tabNew Step:
  • Step Name: Executar sp_UpdateRankingCache
  • Type: Transact-SQL script (T-SQL)
  • Database: MuOnline
  • Command: EXEC sp_UpdateRankingCache
  1. Schedules tabNew Schedule:
  • Name: A cada 10 minutos
  • Frequency: Daily
  • Daily frequency: Occurs every 10 minutes
  • Start/End: 00:00:00 a 23:59:59
  1. Clique em OK para salvar.

Para testar imediatamente, clique com o botão direito no Job → Start Job at Step.

Atenção: Confirme que o serviço SQL Server Agent está definido como Automático em Serviços do Windows (services.msc). Se estiver parado, os Jobs não serão executados e o ranking ficará desatualizado.

Passo 5: Configurar a Conexão PHP ao SQL Server

No seu website, crie o arquivo de configuração de banco de dados. Salve em /web/includes/db_config.php:

<?php
// /web/includes/db_config.php
define('DB_SERVER',   '127.0.0.1');   // IP do SQL Server
define('DB_PORT',     '1433');
define('DB_USER',     'mu_web_user'); // usuário com permissão SELECT
define('DB_PASS',     'SuaSenhaAqui');
define('DB_NAME',     'MuOnline');

function getDbConnection() {
    $connectionOptions = [
        'Database'               => DB_NAME,
        'Uid'                    => DB_USER,
        'PWD'                    => DB_PASS,
        'CharacterSet'           => 'UTF-8',
        'TrustServerCertificate' => true,
    ];
    $conn = sqlsrv_connect(DB_SERVER . ', ' . DB_PORT, $connectionOptions);
    if ($conn === false) {
        error_log('Falha na conexão DB: ' . print_r(sqlsrv_errors(), true));
        return null;
    }
    return $conn;
}
?>
Nota: Crie um login SQL Server dedicado para o website com permissão apenas de SELECT na tabela RankingCache. Nunca use sa ou o usuário do GameServer para conexões web.

Passo 6: Criar a Página de Ranking em PHP

Salve o arquivo em /web/ranking.php:

<?php
require_once 'includes/db_config.php';

$type   = isset($_GET['type']) ? $_GET['type'] : 'level';
$type   = in_array($type, ['level', 'zen']) ? $type : 'level';
$page   = max(1, (int)($_GET['page'] ?? 1));
$limit  = 25;
$offset = ($page - 1) * $limit;

// Mapa de classes Season 6
$classNames = [
    0 => 'Dark Wizard',   1 => 'Soul Master',   2 => 'Grand Master',
    16 => 'Dark Knight',  17 => 'Blade Knight',  18 => 'Blade Master',
    32 => 'Fairy Elf',    33 => 'Muse Elf',      34 => 'High Elf',
    48 => 'Magic Gladiator', 64 => 'Dark Lord',
    80 => 'Summoner',     96 => 'Rage Fighter',
];

$conn = getDbConnection();
$sql  = "SELECT CharacterName, CharClass, CharLevel, CharResets, CharZen, GuildName,
                ROW_NUMBER() OVER (PARTITION BY RankType ORDER BY RankPosition) AS Pos
         FROM RankingCache
         WHERE RankType = ?
         ORDER BY RankPosition
         OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";

$params = [$type, $offset, $limit];
$result = sqlsrv_query($conn, $sql, $params);

$lastUpdate = '';
$luSql      = "SELECT TOP 1 LastUpdate FROM RankingCache WHERE RankType = ?";
$luRes      = sqlsrv_query($conn, $luSql, [$type]);
if ($luRow  = sqlsrv_fetch_array($luRes, SQLSRV_FETCH_ASSOC)) {
    $lastUpdate = $luRow['LastUpdate']->format('d/m/Y H:i');
}
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head><meta charset="UTF-8"><title>Ranking - ViciadosMU</title></head>
<body>
<h1>Ranking <?= $type === 'zen' ? 'Zen' : 'Level/Resets' ?></h1>
<p>Última atualização: <?= htmlspecialchars($lastUpdate) ?></p>
<table border="1" cellpadding="6">
  <tr><th>#</th><th>Personagem</th><th>Classe</th><th>Level</th><th>Resets</th><th>Guild</th></tr>
<?php
$rank = $offset + 1;
while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)):
    $cls = $classNames[$row['CharClass']] ?? 'Desconhecido';
?>
  <tr>
    <td><?= $rank++ ?></td>
    <td><?= htmlspecialchars($row['CharacterName']) ?></td>
    <td><?= htmlspecialchars($cls) ?></td>
    <td><?= (int)$row['CharLevel'] ?></td>
    <td><?= (int)$row['CharResets'] ?></td>
    <td><?= htmlspecialchars($row['GuildName'] ?? '-') ?></td>
  </tr>
<?php endwhile; ?>
</table>
</body>
</html>

Passo 7: Resolver Problemas Comuns

Ranking não atualiza

  • Verifique o serviço SQL Server Agent → services.mscSQL Server Agent (MSSQLSERVER)
  • Execute manualmente no SSMS: EXEC MuOnline..sp_UpdateRankingCache
  • Consulte erros em: SSMS → SQL Server Agent → Error Logs

Página PHP retorna tela em branco

// Adicione no topo do arquivo para depuração (remova em produção)
ini_set('display_errors', 1);
error_reporting(E_ALL);

Verifique se a extensão sqlsrv está habilitada no php.ini:

; No php.ini do XAMPP (C:\xampp\php\php.ini)
extension=php_sqlsrv_74_ts_x64.dll
extension=php_pdo_sqlsrv_74_ts_x64.dll

Erro de conexão "Cannot open database"

Execute no SSMS:

-- Verificar se o usuário web tem acesso
USE MuOnline;
GRANT SELECT ON RankingCache TO mu_web_user;
GRANT EXECUTE ON sp_UpdateRankingCache TO mu_web_user;
Dica: Para servidores com muitos jogadores (500+), considere adicionar um índice na coluna Resets da tabela Character: CREATE INDEX IX_Char_Resets ON Character (Resets DESC, cLevel DESC). Isso acelera a stored procedure de atualização.

Expansões Possíveis

Com a estrutura base funcionando, você pode adicionar:

  • Ranking de Guild: agregue pontos pela soma de resets dos membros via GROUP BY G_Name
  • Ranking de PvP: ordene por PkCount DESC com filtro de contas ativas
  • Histórico de posições: adicione uma tabela RankingHistory e insira snapshots diários via Job separado agendado à meia-noite
  • API JSON: retorne os dados como header('Content-Type: application/json'); echo json_encode($rows); para integrar com Discord bots ou apps mobile

Este sistema escala bem para servidores de pequeno a médio porte. Para servidores com mais de 1.000 jogadores simultâneos, considere migrar o cache para Redis ou memcached e consultar o SQL Server apenas durante a atualização agendada.

Perguntas frequentes

Com que frequência devo atualizar o ranking?

Para servidores ativos, um intervalo de 5 a 15 minutos é suficiente. Use o SQL Server Agent com um Job agendado apontando para a stored procedure de atualização. Intervalos menores que 5 minutos podem sobrecarregar o banco de dados em servidores com muitos jogadores.

O ranking mostra dados desatualizados, o que verificar?

Confirme que o SQL Server Agent está rodando em Serviços do Windows, que o Job está ativo (não pausado) e que a tabela RankingCache possui a coluna LastUpdate sendo atualizada. Execute manualmente: EXEC sp_UpdateRankingCache e verifique se há erros no SQL Server Management Studio.

Como evitar que personagens GM apareçam no ranking?

Adicione um filtro na query principal: WHERE AccountID NOT IN (SELECT memb___id FROM MEMB_INFO WHERE memb_stat = 1) e adicione também uma coluna IsAdmin na tabela de cache para filtrar via PHP, ou mantenha uma tabela exclusion_list com os AccountIDs dos administradores.

Posso exibir rankings por classe de personagem?

Sim. Adicione um filtro na query: AND Class BETWEEN 0 AND 1 para Dark Wizard, BETWEEN 16 AND 17 para Dark Knight, BETWEEN 32 AND 33 para Elf, BETWEEN 48 AND 49 para Magic Gladiator e BETWEEN 64 AND 64 para Dark Lord. Crie abas separadas no website para cada filtro.

EQ

Equipe ViciadosMU

Equipe editorial do ViciadosMU — portal de MU Online no ar desde 2003.

Continue lendo

Artigos relacionados