Sistema de Log de Jugadores Avanzado: Monitoreo Completo en MU
Configura un sistema completo de logs para monitorear acciones de jugadores en MU Online: SQL, archivos de log, alertas automáticas y panel admin.
Por Qué un Sistema de Log Avanzado es Esencial
En servidores privados de MU Online, la ausencia de logs detallados hace imposible investigar dupes de ítems, acusaciones entre jugadores y exploits. El sistema por defecto de MuServer registra eventos básicos, pero con la configuración correcta es posible rastrear cada acción relevante — desde el drop de un ítem Excellent hasta intentos de speed hack — con timestamp preciso y la IP del jugador.
Este tutorial cubre el stack completo: configuración del GameServer, creación de tablas SQL dedicadas, stored procedures de logging, SQL Jobs para alertas automáticas y buenas prácticas de retención de datos.
Paso 1: Habilitar Logs Nativos del GameServer
El archivo central de configuración se encuentra en GameServer/Data/GS_Config.ini. Ábrelo con cualquier editor de texto y localiza o agrega las siguientes claves en la sección [GameServer]:
[GameServer]
; --- Logging ---
LogEnable=1
LogLevel=3
; 1=básico | 2=medio | 3=completo (recomendado para admin)
TradeLog=1
TradeLogLevel=2
DropLog=1
DropLogLevel=2
ChatLog=1
ChatLogLevel=1
; Nivel 1 = solo chat público, 2 = incluye whisper
HackLog=1
PKLog=1
; Directorio de salida de los logs en texto
LogPath=./Log/
Después de guardar, reinicia el GameServer. Los archivos de log se generarán en GameServer/Log/ con la siguiente nomenclatura:
GS_YYYYMMDD.log— log generalTrade_YYYYMMDD.log— intercambios entre jugadoresDrop_YYYYMMDD.log— drops de ítems en el sueloHack_YYYYMMDD.log— eventos de seguridad
Paso 2: Crear Tablas SQL para Log Estructurado
Los logs en archivos de texto son difíciles de consultar. La solución es reflejar los eventos críticos en tablas SQL. Conéctate a la base MuOnline en SQL Server Management Studio y ejecuta:
USE MuOnline;
GO
-- Tabla de log de drops de ítems
CREATE TABLE Log_ItemDrop (
LogID BIGINT IDENTITY(1,1) PRIMARY KEY,
LogDate DATETIME DEFAULT GETDATE(),
CharName VARCHAR(10) NOT NULL,
AccountID VARCHAR(10) NOT NULL,
MapNumber TINYINT NOT NULL,
MapX SMALLINT NOT NULL,
MapY SMALLINT NOT NULL,
ItemIndex SMALLINT NOT NULL,
ItemLevel TINYINT NOT NULL,
ItemOption TINYINT NOT NULL, -- 0=normal, 4=excellent
ItemSerial BIGINT NOT NULL,
DropType TINYINT NOT NULL, -- 1=suelo, 2=trade, 3=warehouse
PlayerIP VARCHAR(20)
);
GO
-- Tabla de log de trades
CREATE TABLE Log_Trade (
LogID BIGINT IDENTITY(1,1) PRIMARY KEY,
LogDate DATETIME DEFAULT GETDATE(),
CharGive VARCHAR(10) NOT NULL,
CharReceive VARCHAR(10) NOT NULL,
ItemIndex SMALLINT NOT NULL,
ItemLevel TINYINT NOT NULL,
ItemOption TINYINT NOT NULL,
ItemSerial BIGINT NOT NULL,
ZenAmount INT DEFAULT 0
);
GO
-- Tabla de alertas para el panel admin
CREATE TABLE T_AdminAlerts (
AlertID INT IDENTITY(1,1) PRIMARY KEY,
AlertDate DATETIME DEFAULT GETDATE(),
AlertType VARCHAR(30) NOT NULL,
CharName VARCHAR(10),
Description VARCHAR(500),
IsRead BIT DEFAULT 0
);
GO
MEMB_INFO y Character de tu base de datos para confirmar el schema.Paso 3: Stored Procedures para Inserción de Logs
Crea procedures que el GameServer invoca vía ODBC (en versiones que soportan extensión SQL) o que puedes ejecutar vía triggers. Para servidores que usan extensión de log SQL nativa:
USE MuOnline;
GO
CREATE PROCEDURE WZ_InsertItemDropLog
@CharName VARCHAR(10),
@AccountID VARCHAR(10),
@MapNumber TINYINT,
@MapX SMALLINT,
@MapY SMALLINT,
@ItemIndex SMALLINT,
@ItemLevel TINYINT,
@ItemOption TINYINT,
@ItemSerial BIGINT,
@DropType TINYINT,
@PlayerIP VARCHAR(20)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Log_ItemDrop
(CharName, AccountID, MapNumber, MapX, MapY,
ItemIndex, ItemLevel, ItemOption, ItemSerial, DropType, PlayerIP)
VALUES
(@CharName, @AccountID, @MapNumber, @MapX, @MapY,
@ItemIndex, @ItemLevel, @ItemOption, @ItemSerial, @DropType, @PlayerIP);
END;
GO
CREATE PROCEDURE WZ_InsertTradeLog
@CharGive VARCHAR(10),
@CharReceive VARCHAR(10),
@ItemIndex SMALLINT,
@ItemLevel TINYINT,
@ItemOption TINYINT,
@ItemSerial BIGINT,
@ZenAmount INT = 0
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Log_Trade
(CharGive, CharReceive, ItemIndex, ItemLevel, ItemOption, ItemSerial, ZenAmount)
VALUES
(@CharGive, @CharReceive, @ItemIndex, @ItemLevel, @ItemOption, @ItemSerial, @ZenAmount);
END;
GO
Paso 4: SQL Job para Detección de Ítems Sospechosos
Configura un SQL Server Agent Job que se ejecute cada 5 minutos y detecte automáticamente drops de ítems con nivel alto u opciones raras:
- Abre SQL Server Management Studio
- Expande SQL Server Agent → clic derecho en Jobs → New Job
- Nombre:
MU_DetectarDropsSospechosos - En Steps → New Step, pega el siguiente script:
USE MuOnline;
GO
-- Detectar drops de ítems Level 13+ o Excellent en los últimos 5 minutos
INSERT INTO T_AdminAlerts (AlertType, CharName, Description)
SELECT
'DROP_SOSPECHOSO',
d.CharName,
'Drop: Item=' + CAST(d.ItemIndex AS VARCHAR) +
' Lv=' + CAST(d.ItemLevel AS VARCHAR) +
' Opt=' + CAST(d.ItemOption AS VARCHAR) +
' Map=' + CAST(d.MapNumber AS VARCHAR) +
' Pos=(' + CAST(d.MapX AS VARCHAR) + ',' + CAST(d.MapY AS VARCHAR) + ')' +
' IP=' + ISNULL(d.PlayerIP, 'N/A')
FROM Log_ItemDrop d
WHERE d.LogDate >= DATEADD(MINUTE, -5, GETDATE())
AND (d.ItemLevel >= 13 OR d.ItemOption >= 4);
-- Detectar trades con ítems Level 15+ (posible dupe)
INSERT INTO T_AdminAlerts (AlertType, CharName, Description)
SELECT
'TRADE_LEVEL15',
t.CharGive,
'Trade: ' + t.CharGive + ' -> ' + t.CharReceive +
' Item=' + CAST(t.ItemIndex AS VARCHAR) +
' Lv=' + CAST(t.ItemLevel AS VARCHAR)
FROM Log_Trade t
WHERE t.LogDate >= DATEADD(MINUTE, -5, GETDATE())
AND t.ItemLevel >= 15;
- En Schedules → New Schedule: Frequency = Daily, Recurs every 5 minutes
- Haz clic en OK para guardar el Job
msdb.dbo.sp_send_dbmail con el contenido de los registros no leídos de T_AdminAlerts.Paso 5: Script Batch para Archivar Logs Antiguos
Los logs se acumulan rápidamente. Crea el archivo GameServer/LogArchive.bat para comprimir y mover logs con más de 30 días:
@echo off
REM Archivo: GameServer/LogArchive.bat
REM Programar en el Programador de tareas de Windows - diariamente a las 03:00
set LOG_DIR=C:\MuServer\GameServer\Log
set ARCHIVE_DIR=C:\MuServer\GameServer\Log\Archive
set DAYS_OLD=30
if not exist "%ARCHIVE_DIR%" mkdir "%ARCHIVE_DIR%"
REM Mover logs antiguos a la carpeta de archivo
forfiles /p "%LOG_DIR%" /s /m *.log /d -%DAYS_OLD% /c "cmd /c move @path %ARCHIVE_DIR%\"
REM Comprimir archivos movidos (requiere 7-Zip instalado en C:\Program Files\7-Zip\)
"C:\Program Files\7-Zip\7z.exe" a "%ARCHIVE_DIR%\logs_%date:~6,4%%date:~3,2%%date:~0,2%.7z" "%ARCHIVE_DIR%\*.log" -sdel
echo Archivado completado: %date% %time%
forfiles.Paso 6: Consultas SQL Útiles para Investigaciones
Utiliza estas queries en el día a día para investigar reportes de jugadores:
-- Historial completo de un jugador en las últimas 24 horas
SELECT LogDate, DropType, ItemIndex, ItemLevel, ItemOption,
MapNumber, MapX, MapY, PlayerIP
FROM Log_ItemDrop
WHERE CharName = 'NombreDelJugador'
AND LogDate >= DATEADD(HOUR, -24, GETDATE())
ORDER BY LogDate DESC;
-- Verificar si un serial de ítem aparece en múltiples jugadores (dupe)
SELECT CharName, LogDate, DropType
FROM Log_ItemDrop
WHERE ItemSerial = 123456789
ORDER BY LogDate;
-- Jugadores con mayor volumen de drops de ítems raros (posible bot farm)
SELECT CharName, COUNT(*) AS TotalDrops
FROM Log_ItemDrop
WHERE ItemLevel >= 10
AND LogDate >= DATEADD(DAY, -7, GETDATE())
GROUP BY CharName
ORDER BY TotalDrops DESC;
-- Alertas no leídas para el panel admin
SELECT AlertDate, AlertType, CharName, Description
FROM T_AdminAlerts
WHERE IsRead = 0
ORDER BY AlertDate DESC;
-- Marcar alertas como leídas después de revisión
UPDATE T_AdminAlerts SET IsRead = 1
WHERE IsRead = 0 AND AlertDate < DATEADD(HOUR, -1, GETDATE());
Mantenimiento y Retención de Datos
Conservar logs indefinidamente consume espacio en disco y degrada el rendimiento de las consultas. Configura una rutina de limpieza en SQL Server Agent:
-- Job de limpieza mensual: eliminar logs con más de 90 días
DELETE FROM Log_ItemDrop WHERE LogDate < DATEADD(DAY, -90, GETDATE());
DELETE FROM Log_Trade WHERE LogDate < DATEADD(DAY, -90, GETDATE());
DELETE FROM T_AdminAlerts WHERE AlertDate < DATEADD(DAY, -30, GETDATE()) AND IsRead = 1;
MuOnline_Archive. Esto preserva el historial sin sobrecargar la base de datos principal.Solución de Problemas Comunes
El GameServer no está escribiendo logs de texto: Verifica que la carpeta GameServer/Log/ exista y que el proceso del GameServer tenga permiso de escritura en ella. En Windows Server, el usuario que ejecuta GameServer.exe necesita permiso de Modificar en la carpeta Log.
La stored procedure no se está invocando: En versiones de MuServer que no soportan extensión SQL nativa para logs, necesitarás middleware o un script que parsee los archivos de texto e inserte nuevas líneas en SQL cada minuto. Crea un script PowerShell que lea GS_YYYYMMDD.log e inserte entradas nuevas en la base de datos como tarea programada.
La tabla Log_ItemDrop ha crecido demasiado: Ejecuta DBCC SHRINKFILE después de la limpieza y reconstruye el índice: ALTER INDEX ALL ON Log_ItemDrop REBUILD. Esto recupera espacio y mantiene el rendimiento de las consultas.
Perguntas frequentes
¿Dónde escribe el GameServer los logs por defecto?
El GameServer escribe logs de texto en la carpeta GameServer/Log/, con archivos separados por fecha en formato GS_YYYYMMDD.log. Cada línea contiene timestamp, tipo de evento y datos del jugador.
¿Cómo habilitar el log de intercambio de ítems entre jugadores?
En GameServer/Data/GS_Config.ini, define TradeLog=1 y TradeLogLevel=2 para registrar todos los ítems intercambiados con código serial, nivel y opciones de cada ítem.
¿Es posible registrar intentos de hack y exploits?
Sí. Define HackLog=1 en GS_Config.ini. Los intentos de packet injection, speed hack y uso de ítems inválidos se registran en la tabla Log_HackCheck de la base MuOnline con la IP del jugador.
¿Cómo crear alertas automáticas cuando un jugador dropea ítems raros?
Crea un SQL Job en SQL Server Agent que se ejecute cada 5 minutos consultando Log_ItemDrop donde ItemLevel >= 13 o ItemOption = 4 (excellent), e inserta alertas en la tabla T_AdminAlerts para mostrarlas en el panel web.