Lewati ke konten utama

Utility Modules

Global utility ala Roblox yang nempel di runtime — task, crypto, datetime, uuid, random, websocket, dan regex. Surface tipis, function-based (kecuali yang emang butuh state), jadi snippet Roblox bisa di-paste tanpa rewrite.


task — Roblox-compat scheduler

Map ke primitive yang udah ada (runThread / removeThread / sleep) jadi script copy-paste dari Roblox jalan tanpa rewrite. Catatan: task.wait pake detik (float), sleep pake milidetik — pilih vocabulary mana pun yang cocok.

task.wait(seconds?)

FieldType
Signature(seconds: number?) → number
Returnsdetik yang di-sleep (default 0 buat single-tick yield)
Asyncyes
task.wait(0.5) -- yield setengah detik
task.wait() -- single-tick yield

task.spawn(fn, ...)

FieldType
Signature(fn: (...any) → (), ...any) → number
Returnsthread handle id, dipake buat task.cancel
local id = task.spawn(function(x, y) print(x + y) end, 2, 3)

task.delay(seconds, fn, ...)

Run fn(args...) setelah seconds lewat. Return handle id buat task.cancel.

task.defer(fn, ...)

Sama kayak spawn tapi single-tick yield dulu — jalan di resumption point berikutnya.

task.cancel(id)

Abort task by handle id. Return true kalau handle match task yang masih hidup.


crypto — hash + encoding

Input/output byte string (Lua string itu binary-safe, bukan UTF-8). Decoder raise kalau input invalid — typo silent gak ke-hide.

FunctionReturns
crypto.sha256(input)hex digest, 64 char
crypto.sha512(input)hex digest, 128 char
crypto.hexEncode(bytes)lower-case hex
crypto.hexDecode(hex)raw bytes
crypto.base64Encode(input)standard base64 (padded =)
crypto.base64Decode(b64)raw bytes
crypto.base64UrlEncode(input)URL-safe base64 (no padding)
crypto.base64UrlDecode(b64)raw bytes
print(crypto.sha256("hello"))
--> "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

local b = crypto.base64Encode("hello world")
print(b) --> "aGVsbG8gd29ybGQ="
print(crypto.base64Decode(b)) --> "hello world"

Belum ada HMAC / signing primitive. Tambah pas script beneran butuh.


datetime — wall-clock helpers

Isi gap yang os.time() / os.date(...) Lua stdlib gak cover: presisi millisecond, ISO-8601 round-trip, konversi UTC vs local eksplisit.

Quick reference

FunctionReturns
datetime.unixSeconds()UTC unix detik saat ini
datetime.unixMillis()UTC unix milidetik saat ini
datetime.iso()"2026-05-05T08:55:07Z"
datetime.format(fmt?)strftime UTC, default ISO-8601
datetime.formatLocal(fmt?)strftime LOCAL TZ
datetime.formatUnix(ts, fmt?)format unix-second timestamp tertentu
datetime.parseIso(s)unix detik, atau nil kalau gagal
datetime.monotonicMillis()wall-clock millis since epoch

Round-trip

local original = "2026-05-05T08:55:07Z"
local secs = datetime.parseIso(original)
local back = datetime.formatUnix(secs) -- default ISO-8601
assert(back == original)

parseIso return nil kalau gagal — script bisa guard tanpa pcall.


uuid — UUID v4

print(uuid.new()) --> "f47ac10b-58cc-4372-a567-0e02b2c3d479"
print(uuid.new("simple")) --> "f47ac10b58cc4372a5670e02b2c3d479"
print(uuid.new("urn")) --> "urn:uuid:f47ac10b-..."

Cryptographically random (UUID v4). Pas buat: per-script run id, idempotency key, filename ephemeral, correlation id di HTTP request.


random — RNG yang lebih ok dari math.random

Dua surface:

  1. Stateless — pake default RNG process-wide non-deterministic.
  2. random.new(seed) userdata — deterministic stream buat run reproducible.

Stateless

print(random.integer(1, 6)) -- inclusive [1, 6]
print(random.number()) -- [0, 1) float
print(random.number(10)) -- [0, 10)
print(random.number(5, 10)) -- [5, 10)
print(random.choice({"a","b"}))
local salt = random.bytes(16) -- 16-byte random string

local t = {1, 2, 3, 4, 5}
random.shuffle(t) -- in place

Seeded (deterministic)

local rng = random.new(42)
for i = 1, 5 do
print(rng:integer(1, 100)) -- selalu sequence yang sama dengan seed=42
end

RandomState punya method yang sama: :integer, :number, :bytes, :choice, :shuffle.


websocket — async client

Surface minimal Roblox-style. connect return (ws, err) jadi script bisa if err then return end tanpa pcall.

websocket.connect(url) → (ws, err)

FieldType
Signature(url: string) → (WebSocket?, string?)
Returns(ws, nil) kalau sukses, (nil, err) kalau gagal
Acceptsws:// dan wss://
local ws, err = websocket.connect("wss://echo.websocket.org")
if err then return print("connect gagal:", err) end

ws:on("message", function(text) print("recv:", text) end)
ws:on("close", function(code, reason) print("closed:", code, reason) end)

ws:send("hello")
sleep(1000)
ws:close()

Method di ws

MethodArgEffect
ws:send(text)stringsend Text frame
ws:sendBinary(bytes)stringsend Binary frame (raw bytes)
ws:close()tutup koneksi (idempotent)
ws:isClosed()true setelah close (lokal atau peer)
ws:on(event, fn)lihat tabelsubscribe event inbound

Event

EventCallback signature
"message"(text: string) — Text frame
"binary"(bytes: string) — Binary frame
"close"(code: number, reason: string) — peer close
"error"(message: string) — read-side error

Catatan

  • Gak ada auto-reconnect / backoff / heartbeat. Script yang butuh wrap connect di loop sendiri.
  • tungstenite udah handle ping/pong internal — code lo gak ngeliat itu.
  • Tiap koneksi spawn 1 tokio task buat read + 1 buat write. Tear-down pas close() atau peer close.

regex — PCRE-style pattern

string.match / string.gmatch Lua bawaan pake Lua pattern yang minimal (gak ada | alternation, character class cuma %w/%d dll, gak ada quantifier group). Module ini expose Rust regex crate jadi script bisa pake engine yang lo udah tau dari bahasa lain.

regex.new(pattern) → (re, err)

Compile sekali, reuse murah. Return (nil, err) kalau syntax error.

local re, err = regex.new([[(\d{4})-(\d{2})-(\d{2})]])
if err then return print(err) end

local m = re:find("today is 2026-05-05 thanks")
-- m = { match = "2026-05-05", start = 10, ["end"] = 19,
-- groups = { "2026", "05", "05" } }

Method di Regex compiled

MethodReturns
re:isMatch(haystack)boolean
re:find(haystack)match-table pertama, atau nil
re:findAll(haystack){RegexMatch} — semua non-overlapping match
re:gmatch(haystack)iterator — for m in re:gmatch(s) do ... end
re:replace(haystack, replacement)string ke-replace (dollar-form $1/$2)
re:split(haystack){string}
re:pattern()source pattern asli

Shape match-table

{
match = "2026-05-05", -- substring full yang match
start = 10, -- 1-based byte offset char pertama
["end"] = 19, -- 1-based byte offset char terakhir (inclusive)
groups = { "2026", "05", "05" }, -- 1-indexed capture group
}

Index matching string.find Lua (1-based, end-inclusive). Group optional yang gak match dateng sebagai nil.

One-shot helper

Buat compare cepet tanpa nyimpen handle compiled:

print(regex.isMatch([[(?i)hello]], "Hello World")) --> true
print(regex.find([[\d+]], "abc 42 def").match) --> "42"
print(regex.replace([[\s+]], " a b c", " ")) --> " a b c"

for _, word in ipairs(regex.split([[\W+]], "hello, world!")) do
print(word)
end

regex.escape(s)

Neutralize semua metachar jadi s match literal. Pake pas lo splice input user ke pattern:

local needle = "1.2.3+x"
local pat = regex.escape(needle)
print(regex.isMatch(pat, "find 1.2.3+x here")) --> true
print(regex.isMatch(pat, "find 1X2X3+x here")) --> false

Replace dengan capture group

replace pake dollar-form group references (regex crate convention), BUKAN Lua %1:

local re = regex.new([[(\w+)@(\w+)]])
print(re:replace("alice@example, bob@test", "$2/$1"))
--> "example/alice, test/bob"

Kapan pake regex.new vs one-shot

  • Hot loop / pattern repeat: regex.new(p) compile sekali, reuse.
  • One-off scrub: regex.replace(p, h, r) dll compile per call — fine buat cold path.

Inline flag

Crate regex support inline flag group: (?i) case-insensitive, (?s) . match newline, (?m) multi-line, (?x) verbose. Combine: (?im)hello dst.


Recipe gabungan — signed-payload echo bot

Sign tiap outbound pake HMAC-style crypto.sha256(secret + payload), attach UUID correlation id, forward response balik ke script:

local SECRET = "shhh"

local ws, err = websocket.connect("wss://echo.websocket.org")
if err then return print(err) end

ws:on("message", function(reply)
print(datetime.iso(), "<", reply)
end)

for i = 1, 5 do
local cid = uuid.new("simple")
local body = string.format('{"id":"%s","i":%d,"ts":%d}', cid, i, datetime.unixSeconds())
local sig = crypto.sha256(SECRET .. body)
ws:send(body .. " sig=" .. sig)
task.wait(0.5)
end

task.wait(1)
ws:close()

Lihat juga

  • Eventsclient:on(event, callback) buat event game-side
  • Examples — pattern script praktis
  • HTTP — request/response client (saudara websocket)
  • JSON — encode/decode tabel JSON