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.
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:
- GameServer/GameServer.ini — defines the global fixed EXP, Drop, and Jewel multipliers at server startup.
- Database (MuOnline) — tables such as
T_EventConfig,T_RateControl(in custom builds), orT_ServerInfocan 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.
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
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
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)
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;
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.