Utility Functions
This guide covers all the helpful utility functions: logging, sounds, browser integration, HTTP requests, JSON, and more.
Logging and Messages
Console Logging
LogPrint(text)
Writes a message to the client console (for debugging).
LogPrint("Plugin initialized successfully!")
LogPrint("Value: " .. tostring(myValue))
In-Game Notifications
NoticeSend(type, message)
Parameters:
type- Notification type:0= Large message in center of screen1= Yellow message at top2= Message in chat
NoticeSend(0, "Welcome to the server!")
NoticeSend(1, "Item received!")
NoticeSend(2, "[System] Maintenance in 10 minutes")
Getting System Messages
MessageGet(index)
Gets a message from the game's message system.
local msg = MessageGet(100)
LogPrint(msg)
Sound System
Playing Sounds
SoundPlay(index)
Plays a game sound by index.
Common sound indices:
- 0-50: UI sounds
- 51-100: Skill sounds
- 101-200: Ambient sounds
SoundPlay(10) -- Click sound
Sound in Buttons
function MyPlugin.renderButton(window, button)
if button.click == 1 then
SoundPlay(10) -- Click sound
elseif button.click == 3 then
SoundPlay(15) -- Confirmation sound
-- Button action...
end
end
Stopping Sounds
SoundStop(index)
Stops a sound that's currently playing.
SoundStop(10)
Game Windows
These functions let you interact with the game's built-in windows.
Opening Game Windows
WindowOpen(index)
Common window indices:
- 1 = Inventory
- 2 = Shop
- 3 = Warehouse
- 4 = Trade
- 5 = Guild
- 6 = Party
if WindowOpen(1) then
LogPrint("Inventory opened!")
end
Show/Hide Windows
WindowShow(index) -- Show window
WindowHide(index) -- Hide window
WindowShow(1) -- Show inventory
WindowHide(1) -- Hide inventory
Browser Integration
Opening URLs
BrowserOpen(url)
Opens a URL in the system's default browser.
BrowserOpen("https://www.google.com")
BrowserOpen("https://discord.gg/myserver")
Example - Button Opening Website
function MyPlugin.renderButton(window, button)
if button.click == 3 then
BrowserOpen("https://myserver.com/ranking")
end
button:renderText("View Ranking", 0, 0, button.w, button.h, 4,
RGBA(255,255,255,255), FontM)
end
HTTP Requests
GET Requests
HttpGetAsync(url, callback)
Callback receives:
code- HTTP status code (200 = success)msg- Response body
HttpGetAsync("https://api.myserver.com/status", function(code, msg)
if code == 200 then
LogPrint("Response: " .. msg)
-- Decode JSON
local data = JsonDecode(msg)
if data then
LogPrint("Players online: " .. data.online)
NoticeSend(1, "Server: " .. data.status)
end
else
LogPrint("HTTP Error: " .. code)
end
end)
POST Requests
HttpPostAsync(url, header, contents, callback)
Parameters:
url- URL to POST toheader- HTTP headerscontents- Request bodycallback- Function called with response
local headers = "Content-Type: application/json"
local body = JsonEncode({
player = "John",
score = 1000
})
HttpPostAsync(
"https://api.myserver.com/scores",
headers,
body,
function(code, msg)
if code == 200 then
LogPrint("Score sent!")
NoticeSend(1, "Score saved successfully!")
else
LogPrint("Error sending score: " .. code)
end
end
)
JSON Handling
Encoding JSON
JsonEncode(value)
Converts a Lua table to JSON string.
local data = {
name = "John",
level = 400,
items = {1, 2, 3},
stats = {
str = 1000,
agi = 800
}
}
local json = JsonEncode(data)
LogPrint(json)
-- {"name":"John","level":400,"items":[1,2,3],"stats":{"str":1000,"agi":800}}
Decoding JSON
JsonDecode(value)
Converts a JSON string to Lua table.
local jsonString = '{"name":"John","level":400}'
local data = JsonDecode(jsonString)
if data then
LogPrint("Name: " .. data.name)
LogPrint("Level: " .. data.level)
end
Complete Example - Save/Load Config
MyPlugin = {
config = {
showHP = true,
showMP = true,
opacity = 0.8
}
}
function MyPlugin:saveConfig()
local json = JsonEncode(self.config)
-- Send to server or save locally
MagicWorld:sendData(PluginPacket.SaveConfig, {json})
NoticeSend(1, "Config saved!")
end
function MyPlugin:loadConfig(jsonString)
local data = JsonDecode(jsonString)
if data then
self.config = data
NoticeSend(1, "Config loaded!")
end
end
Game Information
Server Info
-- GetMainInfo()
-- Returns info about the client
local info = GetMainInfo()
LogPrint("Client version: " .. tostring(info.version))
-- GetWorld()
-- Returns current world/server ID
local world = GetWorld()
LogPrint("World: " .. world)
-- GetWorldName(world)
-- Returns world name
local worldName = GetWorldName(GetWorld())
LogPrint("World name: " .. worldName)
Memory Manipulation
WARNING: Use these carefully! Incorrect use can crash the client.
Reading Memory
-- Read 1 byte (0-255)
local value = MemoryGetByte(0x12345678)
-- Read 2 bytes (0-65535)
local value = MemoryGetWord(0x12345678)
-- Read 4 bytes
local value = MemoryGetDword(0x12345678)
-- Read float
local value = MemoryGetFloat(0x12345678)
-- Read double
local value = MemoryGetDouble(0x12345678)
Writing Memory
-- Write 1 byte
MemorySetByte(0x12345678, 100)
-- Write 2 bytes
MemorySetWord(0x12345678, 5000)
-- Write 4 bytes
MemorySetDword(0x12345678, 100000)
-- Write float
MemorySetFloat(0x12345678, 3.14)
-- Write double
MemorySetDouble(0x12345678, 3.14159265)
Memory Hooks
MemorySetCompleteHook(head, offset, target)
ADVANCED: Creates a complete memory hook. Only use if you know what you're doing!
License System
Check if a plugin is licensed:
GetLicenseAddonEnabled(index)
Returns: true if the plugin is licensed
if GetLicenseAddonEnabled(1001) then
LogPrint("VIP Plugin activated!")
else
LogPrint("VIP Plugin not licensed")
end
Example - License Check
function MyVIPPlugin:showWindow()
if not GetLicenseAddonEnabled(self.licenseId) then
NoticeSend(1, "This feature requires VIP license!")
return false
end
local window = UIWindowGet(self.group, self.index)
if window then
window:setState(1)
return true
end
return false
end
Custom Values
Get custom configuration values:
-- Get integer value
local maxLevel = GetCustomValueAsInt("MaxLevel", 400) -- Default: 400
LogPrint("Max level: " .. maxLevel)
-- Get string value
local serverName = GetCustomValueAsStr("ServerName", "Unknown")
LogPrint("Server name: " .. serverName)
Client Settings
Performance Settings
SetPerformanceState(state)
Changes the client's performance state.
SetPerformanceState(1) -- Performance mode
Custom Titles
SetCustomTitleState(state)
Enables/disables custom titles.
SetCustomTitleState(1) -- Enable custom titles
Cash Shop Window
SetCashShopWindowId(index)
Sets the ID of a custom cash shop window.
SetCashShopWindowId(1000)
Complete Example - Config System
Here's a full config system with HTTP backup:
ConfigSystem = {
index = GetWindowIndex(),
group = UI_GROUP_INGAME,
config = {
soundEnabled = true,
notificationsEnabled = true,
opacity = 1.0,
fontSize = 14,
hotkey = VK_F5
}
}
function ConfigSystem.renderWindow(window)
UIRenderWindow(window, 0, 0, window.w, window.h, 0)
window:renderText("Settings", 0, 10, window.w, 30, 4,
RGBA(255,215,0,255), FontL)
local y = 50
-- Sound
local soundText = ConfigSystem.config.soundEnabled and "On" or "Off"
window:renderText("Sound: " .. soundText, 20, y, window.w-40, 25, 1,
RGBA(255,255,255,255), FontM)
-- Notifications
y = y + 30
local notifText = ConfigSystem.config.notificationsEnabled and "On" or "Off"
window:renderText("Notifications: " .. notifText, 20, y, window.w-40, 25, 1,
RGBA(255,255,255,255), FontM)
-- Opacity
y = y + 30
window:renderText(string.format("Opacity: %.0f%%", ConfigSystem.config.opacity * 100),
20, y, window.w-40, 25, 1, RGBA(255,255,255,255), FontM)
-- Instructions
y = y + 40
window:renderText("Press SPACE to save", 0, y, window.w, 25, 4,
RGBA(200,200,200,255), FontS)
end
function ConfigSystem.updateWindow(window)
if window.state == 0 then
return false
end
if InputCheckChatOpen() then
return true
end
-- Save with SPACE
if InputCheckKeyPress(VK_SPACE, 1) then
ConfigSystem:saveConfig()
end
-- Toggle sound with 1
if InputCheckKeyPress(VK_1, 1) then
ConfigSystem.config.soundEnabled = not ConfigSystem.config.soundEnabled
if ConfigSystem.config.soundEnabled then
SoundPlay(10)
end
end
-- Toggle notifications with 2
if InputCheckKeyPress(VK_2, 1) then
ConfigSystem.config.notificationsEnabled = not ConfigSystem.config.notificationsEnabled
NoticeSend(1, "Notifications " ..
(ConfigSystem.config.notificationsEnabled and "enabled" or "disabled"))
end
return true
end
function ConfigSystem:saveConfig()
local json = JsonEncode(self.config)
LogPrint("Saving config: " .. json)
-- Send to server to save
MagicWorld:sendData(PluginPacket.SaveConfig, {json})
-- HTTP backup
HttpPostAsync(
"https://api.myserver.com/saveconfig",
"Content-Type: application/json",
json,
function(code, msg)
if code == 200 then
NoticeSend(1, "Config saved successfully!")
SoundPlay(15)
else
NoticeSend(1, "Error saving config!")
end
end
)
end
function ConfigSystem:loadConfig()
-- Request config from server
MagicWorld:sendData(PluginPacket.LoadConfig, {})
end
-- Receive config
MagicWorld:pushRecv(PluginPacket.LoadConfig, function(packet)
local json = packet:getString()
if json and json ~= "" then
local data = JsonDecode(json)
if data then
ConfigSystem.config = data
NoticeSend(1, "Config loaded!")
LogPrint("Config loaded: " .. json)
end
end
packet:free()
end)
-- Load on game entry
BridgeFunction:push("OnInGame", function()
ConfigSystem:loadConfig()
end)
Best Practices
-
Always handle HTTP errors - Check
code == 200before processing -
Use LogPrint() for debugging - Helps identify issues quickly during development
-
NoticeSend() is great for user feedback - Use type 1 for important messages, type 2 for general info
-
Be careful with memory manipulation - Only use if you know exactly what you're doing - Errors can crash the client
-
Validate JSON data - Always check if JsonDecode() returned a valid table
-
Sounds improve UX - Use subtle sounds for action feedback - Don't overdo it
Quick Reference
-- Logging
LogPrint("Debug message")
NoticeSend(1, "Notification")
-- Sounds
SoundPlay(10)
SoundStop(10)
-- Browser
BrowserOpen("https://example.com")
-- HTTP
HttpGetAsync(url, function(code, msg) end)
HttpPostAsync(url, headers, body, function(code, msg) end)
-- JSON
local json = JsonEncode(table)
local table = JsonDecode(json)
-- Windows
WindowOpen(1) -- Open inventory
WindowShow(1)
WindowHide(1)
-- License
if GetLicenseAddonEnabled(id) then end
-- Custom values
local value = GetCustomValueAsInt("Key", default)
local text = GetCustomValueAsStr("Key", default)
That's all the utility functions! You now have everything you need to build complete client-side plugins. Next up: complete working examples!