Skip to content
Development
Skill

/roblox-networking

Roblox client-server networking and anti-exploit: RemoteEvent and RemoteFunction contracts, server authority, rate limits, hit validation and replication. Use when a remote trusts the client, exploiters spam remotes or gain items, or hits register wrongly. Not for Luau basics

From plugin
awesome-gamedev-agent-skills
8.6k79 skills

Claude Code

$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill roblox-networking --agent claude-code

SKILL.md

roblox-networking.SKILL.md
name: roblox-networking
description: >
  Roblox client-server networking and anti-exploit: RemoteEvent and RemoteFunction contracts,
  server authority, rate limits, hit validation and replication. Use when a remote trusts the
  client, exploiters spam remotes or gain items, or hits register wrongly. Not for Luau basics
  (`roblox-luau`), saving (`roblox-datastores`) or force and raycast APIs (`roblox-physics`).

Roblox networking

The server decides authoritative state; clients send input or intent. This skill owns the request contract across that boundary: what is sent, who validates it, who receives the result, and how it is tested with more than one client.

Workflow

1. **Inventory the existing protocol.** Find every remote and both endpoints before adding one: `rg -n "OnServerEvent|OnServerInvoke|OnClientEvent|InvokeClient|FireAllClients" src` (or the Studio MCP `script_grep` tool). For each, note direction, sender, payload, frequency, validation, and consumers. Reuse the canonical remote folder; a duplicate remote created because discovery was skipped usually means two handlers apply the same action. 2. **Classify each message.** Client request, server fact, or ephemeral cosmetic sample. Pick reliable event, unreliable event, or request/response from that, not from convenience. 3. **Minimize the payload.** Send stable IDs and intent. Never send a price, damage, ownership result, arbitrary path, or any outcome the server can derive. 4. **Validate in layers, cheapest first.** Rate budget, type/shape/finiteness, allowlisted value, Instance class and ancestry, player permission and state, distance or line of sight, cooldown. Only then do expensive work. 5. **Apply on the server.** The server resolves targets and mutates health, inventory, currency, cooldowns, and progression. Client checks are UX only. 6. **Replicate narrowly.** `FireClient` for private or local facts; broadcast only shared facts. Replicated properties are already a state channel, so do not mirror them through remotes. 7. **Handle time and lifecycle.** Requests arrive after death, respawn, streaming changes, or disconnect. Resolve the current character during handling and clear per-player tables on `PlayerRemoving`. 8. **Run the abuse matrix and capture Output from every side.** With the Studio MCP server connected (`list_roblox_studios` returns a place), start play with `start_stop_play`, drive the pure validator from `execute_luau` on the `Server` datamodel with valid, malformed, NaN, wrong Instance and burst inputs, then read `get_console_output`. `start_stop_play` is one solo client, so for targeted versus broadcast delivery and two-player cases ask the user to run Server & Clients with two clients and paste the server and both client Output panes. Report each case as executed, prepared but not run, or unverified.

Choose the transport

| Primitive | Use | Do not use | |---|---|---| | `RemoteEvent` | ordered, reliable one-way requests and facts | continuous samples where newer replaces older | | `UnreliableRemoteEvent` | ephemeral cosmetic or continuous state that tolerates loss and reordering | purchases, damage, inventory, one-shot transitions | | `RemoteFunction` | bounded client-to-server query that truly needs a reply | server-to-client invocation, long work, ordinary commands |

Never `InvokeClient` from the server: a client that errors makes the server error, a client that leaves makes it throw, and a client that never returns makes it yield forever. Use `FireClient` plus a separate response event.

Delivery rules that change handler design (per connection, per direction):

  • `RemoteEvent` messages arrive in send order, even across different `RemoteEvent`s, but order

covers when each handler *starts*. A handler that yields (`task.wait`, `WaitForChild`, a DataStore call) lets the next message from the same player start before it resumes, so check-then-yield-then-apply code can approve two requests. Claim the cooldown or mark the request in progress before the first yield.

  • A client firing a `RemoteEvent` faster than the throttle is delayed, not dropped; the backlog

still arrives. `UnreliableRemoteEvent` traffic over the throttle or size cap, or with no handler connected, is discarded.

  • Messages sent before a handler connects are queued (bounded) for `RemoteEvent`s and

`RemoteFunction`s. There is no ordering guarantee between a `RemoteFunction` and a `RemoteEvent`; use one remote type or your own sequence number when order matters.

  • The client-to-server throttle is shared by every remote of the same type in the experience, so a

legitimate player sending per-frame reliable events hits it before any attacker does.

Pattern: validate before resolving gameplay

-- ServerScriptService/CombatRequests.server.luau
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")

local attack = ReplicatedStorage.Remotes.Attack
local lastRequest: {[Player]: number} = {}
local RANGE = 12
local COOLDOWN = 0.25

attack.OnServerEvent:Connect(function(player: Player, target: unknown)
    local now = Workspace:GetServerTimeNow()
    if now - (lastRequest[player] or -math.huge) < COOLDOWN then return end
    lastRequest[player] = now

    if typeof(target) ~= "Instance" or not target:IsA("Model") then return end
    if not target:IsDescendantOf(Workspace.Characters) then return end
    local targetHumanoid = target:FindFirstChildOfClass("Humanoid")
    local targetRoot = target:FindFirstChild("HumanoidRootPart")
    local character = player.Character
    local root = character and character:FindFirstChild("HumanoidRootPart")
    local humanoid = character and character:FindFirstChildOfClass("Humanoid")
    if not targetHumanoid or not targetRoot or not root or not humanoid then return end
    if humanoid.Health <= 0 or targetHumanoid.Health
Read more
@gamedev-skills
Ships withawesome-gamedev-agent-skills

<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.

Stars on GitHub

Momentum

stars in total
8.6k
Star history of gamedev-skills/awesome-gamedev-agent-skills on GitHub, a chart by star-history.com

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills13d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react4d252k
@facebook@facebookInstall Skill

Questions about roblox-networking.

Which coding agents can use roblox-networking?
roblox-networking installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.