Skip to main content

Overview

GTProxy provides multiple ways to send packets:
  • Packet structs - Type-safe packet objects
  • Raw bytes - Direct byte manipulation
  • Text packets - Growtopia text protocol
  • TextParse - Key-value text packets

Send API

The send global provides high-level packet sending:

Send to Client

send.to_client
function
packet
Packet
required
The packet struct to send
Send a packet from the proxy to the game client.
local log = LogPacket.new()
log.msg = "Hello from Lua!"
send.to_client(log)

Send to Server

send.to_server
function
packet
Packet
required
The packet struct to send
Send a packet from the proxy to the game server.
local join = JoinRequestPacket.new()
join.world_name = "START"
send.to_server(join)

Packet API

The packet global provides low-level packet manipulation:

Send Raw Bytes

packet.send_raw
function
bytes
table
required
Table of integers (0-255) representing raw bytes
to_server
boolean
required
true to send to server, false to send to client
-- Send to server
packet.send_raw({ 0x03, 0x00, 0x00, 0x00 }, true)

-- Send to client
packet.send_raw({ 0x03, 0x00, 0x00, 0x00 }, false)

Send Text Packet

packet.send_text
function
text
string
required
The text content to send
to_server
boolean
required
true to send to server, false to send to client
message_type
number
Optional message type (defaults to NET_MESSAGE_GAME_MESSAGE)
-- Send with default message type
packet.send_text("action|respawn", true)

-- Send with specific message type
packet.send_text("action|respawn", true, packet.NET_MESSAGE_GENERIC_TEXT)

Send TextParse

packet.send_text_parse
function
text_parse
TextParse
required
The TextParse object to send
to_server
boolean
required
true to send to server, false to send to client
local tp = TextParse.new()
tp:add("action", "respawn")
packet.send_text_parse(tp, true)

Message Type Constants

packet.NET_MESSAGE_GENERIC_TEXT
number
Generic text message type
packet.NET_MESSAGE_GAME_MESSAGE
number
Game message type (default for send_text)
packet.NET_MESSAGE_GAME_PACKET
number
Game packet type

Examples

Send Log Message

command.register("msg", "Send a message", function(ctx)
    if #ctx.args < 1 then
        ctx:reply("Usage: /msg <message>")
        return false
    end
    
    local message = table.concat(ctx.args, " ")
    
    local log = LogPacket.new()
    log.msg = "`2" .. message
    send.to_client(log)
    
    return true
end)

Join World

command.register("warp", "Warp to a world", function(ctx)
    if #ctx.args < 1 then
        ctx:reply("Usage: /warp <world_name>")
        return false
    end
    
    local world_name = ctx.args[1]
    
    local join = JoinRequestPacket.new()
    join.world_name = world_name:upper()
    send.to_server(join)
    
    ctx:reply("`2Warping to ``{}", world_name)
    return true
end)

Send Text Action

command.register("respawn", "Respawn your character", function(ctx)
    packet.send_text("action|respawn", true)
    ctx:reply("`2Respawning...")
    return true
end)

Send TextParse

command.register("dialog", "Show a dialog", function(ctx)
    local tp = TextParse.new()
    tp:add("action", "dialog")
    tp:add("dialog_name", "custom_dialog")
    tp:add("buttonClicked", "ok")
    
    packet.send_text_parse(tp, true)
    return true
end)

Send Raw Packet

command.register("rawtest", "Send raw test packet", function(ctx)
    -- Send a simple 4-byte packet
    local bytes = { 0x04, 0x00, 0x00, 0x00 }
    packet.send_raw(bytes, true)
    
    ctx:reply("`2Raw packet sent")
    return true
end)

Auto-Respawn on Death

event.on("OnKilled", function(ctx)
    logger.info("Player died, auto-respawning...")
    
    scheduler.schedule(2000, function()
        packet.send_text("action|respawn", true)
        logger.info("Respawned")
    end)
end)

Spam Protection

local last_message_time = 0
local MESSAGE_COOLDOWN = 1000  -- 1 second

event.on("Input", function(ctx)
    if ctx:has_packet() then
        local pkt = ctx:get_packet()
        local current_time = os.time() * 1000
        
        if current_time - last_message_time < MESSAGE_COOLDOWN then
            ctx:cancel()
            
            local log = LogPacket.new()
            log.msg = "`4Slow down! ``Wait " .. 
                math.ceil((MESSAGE_COOLDOWN - (current_time - last_message_time)) / 1000) .. 
                " seconds"
            send.to_client(log)
            
            return
        end
        
        last_message_time = current_time
    end
end)

Custom Packet Builder

function send_custom_log(message, to_server)
    local log = LogPacket.new()
    log.msg = message
    
    if to_server then
        send.to_server(log)
    else
        send.to_client(log)
    end
end

command.register("notify", "Send a notification", function(ctx)
    if #ctx.args < 1 then
        ctx:reply("Usage: /notify <message>")
        return false
    end
    
    local message = "`2[Notification] ``" .. table.concat(ctx.args, " ")
    send_custom_log(message, false)
    
    return true
end)

Packet Modification Pattern

When modifying packets in event handlers:
event.on("server:SendToServer", function(ctx)
    if ctx:has_packet() then
        local pkt = ctx:parse()
        
        -- Modify packet fields directly
        if pkt.net_id then
            pkt.net_id = 999
        end
        
        -- IMPORTANT: Cancel original before sending modified
        ctx:cancel()
        send.to_server(pkt)
    end
end)
Always cancel before resendingWhen you modify and resend a packet, you must cancel the original first to avoid sending it twice:
local pkt = ctx:parse()
pkt.field = "modified"

ctx:cancel()  -- Cancel original
send.to_server(pkt)  -- Send modified

Best Practices

Use packet structs when possiblePacket structs provide type safety and are easier to work with:
-- Good
local log = LogPacket.new()
log.msg = "Hello"
send.to_client(log)

-- Only use raw when necessary
packet.send_raw({ 0x04, 0x00, 0x00, 0x00 }, true)
Use text packets for actionsGrowtopia’s action system uses text packets:
packet.send_text("action|respawn", true)
packet.send_text("action|quit", true)

See Also

Events API

Intercept and modify packets

World API

Access world data for packet context