Brazil's biggest MU Online portal — since 2003
Tutorial Advanced Tutoriais

How to Configure Rate Limits and Rate Adjustments by Schedule in MU

Learn how to configure dynamic rate limits and automatic EXP, drop, and rate adjustments by schedule on your MU Online server.

VI ViciadosMU Team · Updated on 3 jul 2026 · ⏱ 12 min read

Rate limits and schedule-based rate adjustments are advanced techniques that let a MU Online server administrator create planned activity peaks, reward players during prime-time hours, and automatically balance the server economy. This guide covers a complete implementation using SQL Server (2008–2019) and the GameServer Season 6 configuration system.

Concept: How MU Online Processes Rates

MuServer reads base rates from two primary sources:

  1. GameServer/GameServer.ini — defines the global fixed EXP, Drop, and Jewel multipliers at server startup.
  2. Database (MuOnline) — tables such as T_EventConfig, T_RateControl (in custom builds), or T_ServerInfo can override these values at runtime without restarting the server.

The strategy in this tutorial is to keep the .ini with conservative base values and use SQL Server Agent Jobs (or Windows Task Scheduler) to inject dynamic multipliers into the database configuration table, which the GameServer reads periodically.

Nota: This approach works on Season 6 Episode 3 servers (the most widespread build) with the MuOnline database running on SQL Server 2008 R2 or later. Earlier builds may require a GameServer restart to apply .ini changes.

Step 1: Base Configuration in GameServer.ini

Locate the main configuration file:

GameServer/GameServer.ini

Set the base values that will serve as the minimum reference (outside bonus hours):

[GameServerInfo]
ExpRate=30
DropRate=30
MoneyDropRate=30
JewelDropRate=30
MasterExpRate=15
Atenção: Do not set high values here. These are the "normal hours" multipliers. Peak-hour bonuses will be added via the database.

Step 2: Create the Rate Control Table in the Database

Connect to SQL Server Management Studio (SSMS) and execute against the MuOnline database:

USE MuOnline;
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE name = 'T_RateSchedule' AND type = 'U')
BEGIN
    CREATE TABLE T_RateSchedule (
        ScheduleID      INT IDENTITY(1,1) PRIMARY KEY,
        StartHour       TINYINT NOT NULL,   -- 0-23
        EndHour         TINYINT NOT NULL,   -- 0-23 (inclusive)
        WeekDay         TINYINT NOT NULL,   -- 0=All, 1=Sun, 2=Mon... 7=Sat
        MultExpRate     DECIMAL(5,2) NOT NULL DEFAULT 1.00,
        MultDropRate    DECIMAL(5,2) NOT NULL DEFAULT 1.00,
        MultJewelRate   DECIMAL(5,2) NOT NULL DEFAULT 1.00,
        MultMasterExp   DECIMAL(5,2) NOT NULL DEFAULT 1.00,
        Description     VARCHAR(100) NULL,
        Active          BIT NOT NULL DEFAULT 1
    );
END
GO

Insert the bonus time windows you want:

-- Weekend bonus (Sat & Sun, all day) - EXP and Drop doubled
INSERT INTO T_RateSchedule (StartHour, EndHour, WeekDay, MultExpRate, MultDropRate, MultJewelRate, MultMasterExp, Description)
VALUES (0, 23, 1, 2.00, 1.50, 1.50, 2.00, 'Full Sunday Bonus');

INSERT INTO T_RateSchedule (StartHour, EndHour, WeekDay, MultExpRate, MultDropRate, MultJewelRate, MultMasterExp, Description)
VALUES (0, 23, 7, 2.00, 1.50, 1.50, 2.00, 'Full Saturday Bonus');

-- Prime time (every day, 8pm-11pm) - +50% EXP
INSERT INTO T_RateSchedule (StartHour, EndHour, WeekDay, MultExpRate, MultDropRate, MultJewelRate, MultMasterExp, Description)
VALUES (20, 23, 0, 1.50, 1.00, 1.00, 1.50, 'Nightly Happy Hour');

-- Late night (every day, 12am-8am) - reduced rates
INSERT INTO T_RateSchedule (StartHour, EndHour, WeekDay, MultExpRate, MultDropRate, MultJewelRate, MultMasterExp, Description)
VALUES (0, 8, 0, 0.80, 0.80, 0.80, 0.80, 'Late Night Reduced Rate');
GO

Step 3: Create the Current Rate State Table

This table is read by the GameServer (or a web panel) to display the current active rates:

USE MuOnline;
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE name = 'T_RateActive' AND type = 'U')
BEGIN
    CREATE TABLE T_RateActive (
        ID              INT PRIMARY KEY DEFAULT 1,
        ExpRateActive   INT NOT NULL DEFAULT 30,
        DropRateActive  INT NOT NULL DEFAULT 30,
        JewelRateActive INT NOT NULL DEFAULT 30,
        MasterExpActive INT NOT NULL DEFAULT 15,
        LastUpdated     DATETIME NOT NULL DEFAULT GETDATE(),
        SourceApplied   VARCHAR(100) NULL
    );

    -- Single row (global state record)
    INSERT INTO T_RateActive (ID, ExpRateActive, DropRateActive, JewelRateActive, MasterExpActive)
    VALUES (1, 30, 30, 30, 15);
END
GO

Step 4: Rate Application Stored Procedure

USE MuOnline;
GO

CREATE OR ALTER PROCEDURE sp_ApplyScheduledRate
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @CurrentHour  TINYINT = DATEPART(HOUR, GETDATE());
    DECLARE @CurrentDay   TINYINT = DATEPART(WEEKDAY, GETDATE()); -- 1=Sun, 7=Sat

    -- Base rates (matching GameServer.ini constants)
    DECLARE @BaseExp    INT = 30;
    DECLARE @BaseDrop   INT = 30;
    DECLARE @BaseJewel  INT = 30;
    DECLARE @BaseMaster INT = 15;

    -- Multipliers to be calculated (highest specificity wins)
    DECLARE @MultExp    DECIMAL(5,2) = 1.00;
    DECLARE @MultDrop   DECIMAL(5,2) = 1.00;
    DECLARE @MultJewel  DECIMAL(5,2) = 1.00;
    DECLARE @MultMaster DECIMAL(5,2) = 1.00;
    DECLARE @Source     VARCHAR(100) = 'Default';

    -- Select the most specific active rule for the current moment
    -- WeekDay=0 is wildcard; day-specific rules take priority
    SELECT TOP 1
        @MultExp    = MultExpRate,
        @MultDrop   = MultDropRate,
        @MultJewel  = MultJewelRate,
        @MultMaster = MultMasterExp,
        @Source     = Description
    FROM T_RateSchedule
    WHERE Active = 1
      AND @CurrentHour >= StartHour
      AND @CurrentHour <= EndHour
      AND (WeekDay = @CurrentDay OR WeekDay = 0)
    ORDER BY 
        CASE WHEN WeekDay = @CurrentDay THEN 0 ELSE 1 END ASC,  -- Specific day first
        EndHour - StartHour ASC;                                  -- Narrower window = more specific

    -- Update T_RateActive with calculated values
    UPDATE T_RateActive
    SET
        ExpRateActive   = CAST(@BaseExp    * @MultExp    AS INT),
        DropRateActive  = CAST(@BaseDrop   * @MultDrop   AS INT),
        JewelRateActive = CAST(@BaseJewel  * @MultJewel  AS INT),
        MasterExpActive = CAST(@BaseMaster * @MultMaster AS INT),
        LastUpdated     = GETDATE(),
        SourceApplied   = @Source
    WHERE ID = 1;
END;
GO

Test the procedure manually:

EXEC sp_ApplyScheduledRate;
SELECT * FROM T_RateActive;

Step 5: Schedule Automatic Execution via SQL Server Agent

In SSMS, navigate to: SQL Server Agent → Jobs → New Job

Or execute via T-SQL:

USE msdb;
GO

EXEC sp_add_job
    @job_name = N'MU_UpdateScheduledRates';

EXEC sp_add_jobstep
    @job_name      = N'MU_UpdateScheduledRates',
    @step_name     = N'Run sp_ApplyScheduledRate',
    @command       = N'EXEC MuOnline.dbo.sp_ApplyScheduledRate',
    @database_name = N'MuOnline';

-- Runs every 15 minutes
EXEC sp_add_schedule
    @schedule_name       = N'Every_15min',
    @freq_type           = 4,       -- Daily
    @freq_interval       = 1,
    @freq_subday_type    = 4,       -- Minutes
    @freq_subday_interval = 15;

EXEC sp_attach_schedule
    @job_name      = N'MU_UpdateScheduledRates',
    @schedule_name = N'Every_15min';

EXEC sp_add_jobserver
    @job_name = N'MU_UpdateScheduledRates';
GO
Dica: If using SQL Server Express (no Agent), create a file called update_rates.bat in C:\MuServer\Scripts\ with the content: sqlcmd -S .\SQLEXPRESS -d MuOnline -E -Q "EXEC dbo.sp_ApplyScheduledRate" and schedule it in Windows Task Scheduler to run every 15 minutes.

Step 6: Integrate with GameServer (Real-Time Rate Limit)

For the GameServer to apply database rates without restarting, some S6 builds support GM commands via socket. Use the GameServer console command:

/setexp [value]
/setdrop [value]

Automate via a batch script that reads T_RateActive and sends the commands:

@echo off
REM C:\MuServer\Scripts\sync_rates.bat

FOR /F "tokens=1" %%A IN ('sqlcmd -S .\MSSQLSERVER -d MuOnline -E -h-1 -Q "SET NOCOUNT ON; SELECT ExpRateActive FROM T_RateActive WHERE ID=1"') DO SET EXP=%%A
FOR /F "tokens=1" %%A IN ('sqlcmd -S .\MSSQLSERVER -d MuOnline -E -h-1 -Q "SET NOCOUNT ON; SELECT DropRateActive FROM T_RateActive WHERE ID=1"') DO SET DROP=%%A

echo Current EXP Rate: %EXP%
echo Current DROP Rate: %DROP%

REM Send to GameServer console via named pipe or admin tool
REM (implementation varies by build - consult your MuServer documentation)
Nota: Builds that do not support runtime rate changes require a GameServer restart. In that case, schedule restarts at the transition hours (e.g., 8:00 PM and 11:00 PM) using the automatic restart script.

Step 7: Connection Rate Limiting (ConnectServer)

Beyond EXP/Drop rates, limit the number of simultaneous connections in:

ConnectServer/ConnectServer.ini
[ServerInfo]
MaxConnections=500
MaxConnectionsPerIP=3
ConnectionTimeout=30
LoginRateLimit=5
; LoginRateLimit = max login attempts per IP within 60 seconds

For suspicious packet rate limiting, edit:

GameServer/GameServer.ini
[AntiHack]
PacketFloodLimit=100
; Maximum packets per second per connection before disconnecting
PacketFloodAction=1
; 0=Log only, 1=Kick, 2=Temporary ban
BanDuration=30
; Temporary ban duration in minutes

Verification and Troubleshooting

Check the currently applied rate:

SELECT 
    ExpRateActive,
    DropRateActive,
    JewelRateActive,
    MasterExpActive,
    LastUpdated,
    SourceApplied
FROM MuOnline.dbo.T_RateActive
WHERE ID = 1;

Check job execution history:

SELECT 
    j.name AS JobName,
    h.run_date,
    h.run_time,
    h.run_status,   -- 1=Success, 0=Failure
    h.message
FROM msdb.dbo.sysjobhistory h
JOIN msdb.dbo.sysjobs j ON h.job_id = j.job_id
WHERE j.name = 'MU_UpdateScheduledRates'
ORDER BY h.run_date DESC, h.run_time DESC;
Atenção: Always back up the T_RateSchedule table before changing schedule rules. An incorrect configuration can apply zero rates (MultExpRate=0), preventing all player progression on the server.

Emergency reset to default rates:

UPDATE MuOnline.dbo.T_RateActive
SET ExpRateActive=30, DropRateActive=30, JewelRateActive=30, MasterExpActive=15,
    SourceApplied='Emergency Manual Reset', LastUpdated=GETDATE()
WHERE ID=1;

Perguntas frequentes

Can I apply different rates for VIP and non-VIP accounts at the same time?

Yes. Use the T_UserProperty or T_AccountCharacter table to filter by VIP account. Create a stored procedure that checks the VipLevel field before applying the multiplier, e.g.: IF @VipLevel >= 1 SET @ExpMult = @ExpMult * 1.5.

SQL Agent is disabled on SQL Server Express — how do I schedule?

SQL Server Express does not include SQL Agent. Use the Windows Task Scheduler to run a .bat script that calls SQLCMD, e.g.: sqlcmd -S localhost -d MuOnline -Q \"EXEC sp_ApplyScheduledRate\" -E every 15–30 minutes.

How do I avoid conflicts between the GameServer.ini rate limit and the database rates?

The GameServer.ini values are the base multipliers. The stored procedures apply a second multiplier on top. Keep the .ini at ExpRate=1 and manage everything from the database to prevent accidental double-multiplication.

Can I configure rates per specific map in addition to schedule?

Yes. The T_MapConfig table (in some S6 builds) or custom logic in the stored procedure can check MapNumber and apply different rates. Combine with DATEPART(HOUR, GETDATE()) for simultaneous map AND time-based rates.

VI

ViciadosMU Team

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

Keep reading

Related articles