A complete command that cycles through rainbow colors on your character’s skin.
Full Script
Key Features
local rainbow = {}local is_active = falselocal current_task_id = nillocal current_color_index = 0local RAINBOW_COLORS = { 0xFF0000FF, -- Red 0xFF3300FF, -- Red-Orange 0xFF6600FF, -- Orange 0xFF9900FF, 0xFFCC00FF, -- Yellow-Orange 0xFFFF00FF, -- Yellow 0x99FF00FF, 0x00FF00FF, -- Green 0x00FF99FF, 0x00FFFFFF, -- Cyan 0x0099FFFF, 0x0000FFFF, -- Blue 0x000099FF, 0x6600FFFF, -- Indigo 0x9900FFFF -- Purple}local DEFAULT_INTERVAL = 200local MIN_INTERVAL = 50local MAX_INTERVAL = 5000local function send_next_color() local net_id = world:get_local_net_id() if net_id < 0 then if is_active then stop_rainbow() logger.info("Rainbow effect stopped (exited world)") end return end local color = RAINBOW_COLORS[current_color_index + 1] local pkt = OnChangeSkinPacket.new() pkt.net_id = net_id pkt.skin = color send.to_client(pkt) current_color_index = (current_color_index + 1) % #RAINBOW_COLORSendlocal function toggle_on(ctx, interval) current_task_id = scheduler.schedule_periodic(interval, function() send_next_color() return true end) is_active = true current_color_index = 0 send_next_color() ctx:reply("`2Rainbow effect started ``(speed: {}ms)", interval)endlocal function stop_rainbow() if current_task_id ~= nil and scheduler.is_pending(current_task_id) then scheduler.cancel(current_task_id) current_task_id = nil end is_active = falseendlocal function toggle_off(ctx) stop_rainbow() ctx:reply("`2Rainbow effect stopped")endlocal function parse_interval(args) if #args == 0 then return DEFAULT_INTERVAL, nil end local speed_str = args[1] local speed_ms = tonumber(speed_str) if speed_ms == nil then return DEFAULT_INTERVAL, "Invalid speed value '" .. speed_str .. "'" end if speed_ms < MIN_INTERVAL then return DEFAULT_INTERVAL, "Speed too slow (min " .. MIN_INTERVAL .. "ms)" end if speed_ms > MAX_INTERVAL then return DEFAULT_INTERVAL, "Speed too fast (max " .. MAX_INTERVAL .. "ms)" end return speed_ms, nilendcommand.register("rainbow", "Toggle rainbow skin effect", function(ctx) local net_id = world:get_local_net_id() if net_id < 0 then ctx:reply("`4Error: ``You are not in a world") return false end if is_active then toggle_off(ctx) return true end local interval, error_msg = parse_interval(ctx.args) if error_msg then ctx:reply("`4Error: ``" .. error_msg) return false end toggle_on(ctx, interval) return trueend)logger.info("Rainbow command loaded")
What it demonstrates:
Periodic task scheduling with scheduler.schedule_periodic
Task cancellation with scheduler.cancel
Command registration with argument parsing
World state checking with world:get_local_net_id
Packet sending with send.to_client
Input validation and error handling
Usage:
/rainbow - Toggle rainbow effect (default 200ms)/rainbow 100 - Toggle with 100ms interval/rainbow off - Stop rainbow effect
command.register("say", "Echo a message to the client", function(ctx) if #ctx.args < 1 then ctx:reply("Usage: /say <message>") return false end local message = table.concat(ctx.args, " ") local log = LogPacket.new() log.msg = message send.to_client(log) return trueend)command.register("echo", function(ctx) if #ctx.args < 1 then ctx:reply("Usage: /echo <message>") return false end local message = table.concat(ctx.args, " ") local log = LogPacket.new() log.msg = message send.to_client(log) return trueend)logger.info("Command test script loaded")
local function test_local_player() local local_player = world:get_local_player() if local_player then logger.info("[Test 1] Local player found!") logger.info("[Test 1] Name: " .. local_player.name) logger.info("[Test 1] Net ID: " .. local_player.net_id) logger.info("[Test 1] User ID: " .. local_player.user_id) logger.info("[Test 1] Country: " .. local_player.country_code) logger.info("[Test 1] Position: (" .. local_player.position.x .. ", " .. local_player.position.y .. ")") logger.info("[Test 1] Is Local: " .. tostring(local_player.is_local)) else logger.warn("[Test 1] No local player found (not spawned yet?)") endendlocal function test_local_net_id() local local_net_id = world:get_local_net_id() logger.info("[Test 2] Local Net ID: " .. local_net_id)endlocal function test_list_players() local players = world:get_players() logger.info("[Test 3] Players in world: " .. #players) for net_id, player in pairs(players) do logger.info("[Test 3] Player " .. player.net_id .. " - " .. player.name .. " (Pos: " .. player.position.x .. ", " .. player.position.y .. ")") endendlocal function test_find_player() local local_net_id = world:get_local_net_id() if local_net_id >= 0 then local player = world:get_player(local_net_id) if player then logger.info("[Test 4] Found player by net_id " .. local_net_id .. ": " .. player.name) else logger.warn("[Test 4] Could not find player by net_id " .. local_net_id) end else logger.warn("[Test 4] Cannot test - no local net_id") endendlocal function test_collision_data() local local_player = world:get_local_player() if local_player then local col = local_player.collision logger.info("[Test 5] Collision: x=" .. col.x .. ", y=" .. col.y .. ", z=" .. col.z .. ", w=" .. col.w) logger.info("[Test 5] Invisible: " .. local_player.invisible .. ", Mod State: " .. local_player.mod_state) endend
test_local_player()test_local_net_id()test_list_players()test_find_player()test_collision_data()event.on("OnSpawn", function(ctx) if ctx:has_packet() then local pkt = ctx:get_packet() logger.info("[Event] Player spawned: " .. pkt.name) test_local_player() test_list_players() endend)scheduler.schedule_periodic(5000, function() logger.info("[Test 7] Periodic player check...") test_local_player() test_list_players() return trueend)logger.info("World test script loaded")
event.on("ServerBoundPacket", function(ctx) local pkt = ctx:get_packet() if not pkt then return end if pkt:has_raw_data() then logger.debug("[Raw] " .. #pkt.raw .. " bytes, modified=" .. tostring(pkt:is_modified())) end if pkt.text_parse then local action = pkt.text_parse:get("action") if action ~= "" then logger.info("[Text] Action: " .. action) end elseif pkt.game_packet then logger.info("[Game] Type: " .. tostring(pkt.game_packet.type) .. " NetID: " .. pkt.game_packet.net_id) if pkt.game_packet.type == packet.PacketType.PACKET_STATE then logger.info(string.format("[State] Pos: %.1f, %.1f", pkt.game_packet.pos_x, pkt.game_packet.pos_y)) end if pkt.game_packet.flags & packet.PacketFlag.PACKET_FLAG_ON_JUMP ~= 0 then logger.info("[Game] Player Jumped!") end elseif pkt.variant then logger.info("[Variant] Function: " .. tostring(pkt.variant:get(0))) endend)event.on("OnSendToServer", function(ctx) local pkt = ctx:get_packet() if not pkt then return end logger.info("[OnSendToServer] Port: " .. tostring(pkt.port) .. " Token: " .. tostring(pkt.token)) logger.info("[OnSendToServer] Address: " .. pkt.address .. " User: " .. tostring(pkt.user))end)event.on("Input", function(ctx) local pkt = ctx:get_packet() if not pkt then return end logger.info("[Chat] " .. pkt.text) if pkt.text == "!hello" then ctx:cancel() local response = LogPacket.new() response.msg = "Hello from Lua!" send.to_client(response) elseif pkt.text == "!rawtest" then if pkt:has_raw_data() then logger.info("[Raw] " .. #pkt.raw .. " bytes, modified=" .. tostring(pkt:is_modified())) end ctx:cancel() elseif pkt.text == "!modifytest" then pkt.text = "modified message" pkt:mark_modified() logger.info("[Modified] Packet marked as modified") endend)logger.info("Event test script loaded")
Check arguments, player state, and data before using:
if #ctx.args < 1 then ctx:reply("Usage: /command <arg>") return falseendlocal player = world:get_local_player()if not player then ctx:reply("`4Error: ``Not in a world") return falseend
Clean up resources
Cancel tasks and clean up state:
event.on("server:Disconnect", function(ctx) if current_task_id then scheduler.cancel(current_task_id) current_task_id = nil endend)