El mayor portal de MU Online de Brasil — desde 2003
Tutorial Avanzado Tutoriais

Cómo Implementar Sistema de Ranking Automático en el Website de MU

Aprende a crear un sistema de ranking automático integrado con la base de datos SQL Server de tu servidor MU Online, con actualizaciones en tiempo real via PHP.

EQ Equipo ViciadosMU · Actualizado el 3 jul 2026 · ⏱ 12 min de lectura

Mostrar un ranking actualizado automáticamente es una de las funciones más valoradas por los jugadores de servidores privados de MU Online. Esta guía explica cómo integrar la base de datos SQL Server de tu instalación MuServer (Season 6 en adelante) con un website en PHP para generar rankings de personajes, resets y guilds — sin intervención manual.

Requisitos Previos

Antes de comenzar, confirma que tienes:

  • Acceso a SQL Server Management Studio (SSMS) con permisos de lectura/escritura en la base de datos MuOnline
  • PHP 7.4+ con la extensión sqlsrv o pdo_sqlsrv instalada (XAMPP o AppServ en Windows Server)
  • Acceso al SQL Server Agent para programar Jobs
  • Permiso para crear tablas y stored procedures en la base de datos
Nota: Este tutorial usa la base de datos estándar MuOnline del MuServer Season 6. Versiones anteriores (S2/S3) usan estructuras de tablas ligeramente diferentes — adapta los nombres de columnas según sea necesario consultando tu propia tabla Character.

Paso 1: Entender la Estructura de las Tablas Relevantes

El MuServer almacena los datos de personaje en la tabla Character dentro de la base de datos MuOnline. Las columnas más usadas para ranking son:

-- Verificar estructura de la tabla Character
USE MuOnline;
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Character'
ORDER BY ORDINAL_POSITION;

Columnas esenciales para ranking:

ColumnaDescripción
NameNombre del personaje
AccountIDCuenta vinculada
cLevelLevel actual
ClassClase del personaje (byte)
ResetsNúmero de resets (si está configurado)
PkCountConteo de PK
MoneyZen del personaje
MapNumberMapa actual (para verificar si está online)

Paso 2: Crear la Tabla de Caché de Ranking

En lugar de consultar la tabla Character directamente en cada solicitud del website, crea una tabla de caché dedicada. Esto evita lentitud en la base de datos durante picos de acceso.

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

Paso 3: Crear el Stored Procedure de Actualización

El stored procedure a continuación borra y recrea los datos de caché para cada tipo de ranking. Ejecútalo en SSMS para crearlo:

USE MuOnline;
GO

CREATE PROCEDURE sp_UpdateRankingCache
AS
BEGIN
    SET NOCOUNT ON;

    -- Limpiar caché anterior
    DELETE FROM RankingCache;

    -- Ranking por Level y 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;

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

    PRINT 'RankingCache actualizado correctamente.';
END;
GO
Dica: La exclusión con memb_stat = 1 filtra cuentas de GM. Si tu servidor usa una columna diferente para marcar administradores, ajusta el filtro según la estructura de tu MEMB_INFO.

Paso 4: Programar Actualización Automática con SQL Server Agent

Crea un Job en el SQL Server Agent para ejecutar el procedure automáticamente cada 10 minutos:

  1. Abre SSMS → expande SQL Server Agent → clic derecho en JobsNew Job
  2. Pestaña General: Name = Actualizar Ranking MU
  3. Pestaña StepsNew Step:
  • Step Name: Ejecutar sp_UpdateRankingCache
  • Type: Transact-SQL script (T-SQL)
  • Database: MuOnline
  • Command: EXEC sp_UpdateRankingCache
  1. Pestaña SchedulesNew Schedule:
  • Name: Cada 10 minutos
  • Frequency: Daily
  • Daily frequency: Occurs every 10 minutes
  • Start/End: 00:00:00 a 23:59:59
  1. Haz clic en OK para guardar.

Para probar de inmediato, haz clic derecho en el Job → Start Job at Step.

Atenção: Asegúrate de que el servicio SQL Server Agent esté configurado como Automático en Servicios de Windows (services.msc). Si está detenido, los Jobs no se ejecutarán y el ranking quedará desactualizado.

Paso 5: Configurar la Conexión PHP al SQL Server

En tu website, crea el archivo de configuración de base de datos. Guárdalo en /web/includes/db_config.php:

<?php
// /web/includes/db_config.php
define('DB_SERVER',   '127.0.0.1');   // IP del SQL Server
define('DB_PORT',     '1433');
define('DB_USER',     'mu_web_user'); // usuario con permiso SELECT únicamente
define('DB_PASS',     'TuContraseñaAqui');
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('Falla en conexión DB: ' . print_r(sqlsrv_errors(), true));
        return null;
    }
    return $conn;
}
?>
Nota: Crea un login de SQL Server dedicado para el website con permiso únicamente de SELECT en la tabla RankingCache. Nunca uses sa ni el usuario del GameServer para conexiones web.

Paso 6: Crear la Página de Ranking en PHP

Guarda el archivo en /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 clases 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="es">
<head><meta charset="UTF-8"><title>Ranking - ViciadosMU</title></head>
<body>
<h1>Ranking <?= $type === 'zen' ? 'Zen' : 'Level/Resets' ?></h1>
<p>Última actualización: <?= htmlspecialchars($lastUpdate) ?></p>
<table border="1" cellpadding="6">
  <tr><th>#</th><th>Personaje</th><th>Clase</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']] ?? 'Desconocido';
?>
  <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>

Paso 7: Resolver Problemas Comunes

El ranking no se actualiza

  • Verifica el servicio SQL Server Agent → services.mscSQL Server Agent (MSSQLSERVER)
  • Ejecuta manualmente en SSMS: EXEC MuOnline..sp_UpdateRankingCache
  • Revisa errores en: SSMS → SQL Server Agent → Error Logs

La página PHP devuelve pantalla en blanco

// Agrega al inicio del archivo para depuración (eliminar en producción)
ini_set('display_errors', 1);
error_reporting(E_ALL);

Verifica que la extensión sqlsrv esté habilitada en php.ini:

; En el php.ini de XAMPP (C:\xampp\php\php.ini)
extension=php_sqlsrv_74_ts_x64.dll
extension=php_pdo_sqlsrv_74_ts_x64.dll

Error de conexión "Cannot open database"

Ejecuta en SSMS:

-- Verificar que el usuario web tenga acceso
USE MuOnline;
GRANT SELECT ON RankingCache TO mu_web_user;
GRANT EXECUTE ON sp_UpdateRankingCache TO mu_web_user;
Dica: Para servidores con muchos jugadores (500+), considera agregar un índice en la columna Resets de la tabla Character: CREATE INDEX IX_Char_Resets ON Character (Resets DESC, cLevel DESC). Esto acelera significativamente el stored procedure de actualización.

Expansiones Posibles

Con la estructura base funcionando, puedes agregar:

  • Ranking de Guild: agrega puntos sumando los resets de los miembros via GROUP BY G_Name
  • Ranking de PvP: ordena por PkCount DESC con filtro de cuentas activas
  • Historial de posiciones: agrega una tabla RankingHistory e inserta snapshots diarios via un Job separado programado a medianoche
  • API JSON: retorna los datos con header('Content-Type: application/json'); echo json_encode($rows); para integrar con bots de Discord o apps móviles

Este sistema escala bien para servidores de pequeño a mediano tamaño. Para servidores con más de 1.000 jugadores simultáneos, considera migrar la capa de caché a Redis o memcached y consultar el SQL Server únicamente durante las actualizaciones programadas.

Perguntas frequentes

¿Con qué frecuencia debo actualizar el ranking?

Para servidores activos, un intervalo de 5 a 15 minutos es suficiente. Usa el SQL Server Agent con un Job programado apuntando al stored procedure de actualización. Intervalos menores a 5 minutos pueden sobrecargar la base de datos en servidores con muchos jugadores.

El ranking muestra datos desactualizados, ¿qué verificar?

Confirma que el servicio SQL Server Agent está corriendo en Servicios de Windows, que el Job está activo y que la tabla RankingCache tiene la columna LastUpdate actualizándose. Ejecuta manualmente: EXEC sp_UpdateRankingCache y verifica si hay errores en SQL Server Management Studio.

¿Cómo evitar que personajes GM aparezcan en el ranking?

Agrega un filtro en la query principal: WHERE AccountID NOT IN (SELECT memb___id FROM MEMB_INFO WHERE memb_stat = 1). También puedes mantener una tabla exclusion_list con los AccountIDs de los administradores y hacer JOIN contra ella.

¿Puedo mostrar rankings filtrados por clase de personaje?

Sí. Agrega un filtro de clase en la 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, y BETWEEN 64 AND 64 para Dark Lord. Crea pestañas separadas en el website para cada filtro.

EQ

Equipo ViciadosMU

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

Sigue leyendo

Artículos relacionados