Skip to main content

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 screen
    • 1 = Yellow message at top
    • 2 = 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 to
  • header - HTTP headers
  • contents - Request body
  • callback - 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

  1. Always handle HTTP errors - Check code == 200 before processing

  2. Use LogPrint() for debugging - Helps identify issues quickly during development

  3. NoticeSend() is great for user feedback - Use type 1 for important messages, type 2 for general info

  4. Be careful with memory manipulation - Only use if you know exactly what you're doing - Errors can crash the client

  5. Validate JSON data - Always check if JsonDecode() returned a valid table

  6. 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!