roblox-networking について
roblox-networkingは、クライアントとサーバー間の通信を設計・保護するRoblox開発者向けスキルです。サーバー権威の状態、ペイロード検証、レプリケーションの選択、マルチプレイヤーでの不正テストを扱います。
主な機能
- 01既存のリモートプロトコルの整理
- 02メッセージの意味に応じた転送方式の選択
- 03ペイロードとプレイヤー状態の検証
- 04サーバーでのゲーム状態変更
- 05リクエスト頻度の制限
- 06マルチプレイヤーと不正ケースのテスト
活用シーン
- 01クライアントによるダメージや価格の指定防止
- 02Instanceを対象とするリモートの保護
- 03過剰なリモート通信の削減
- 04リスポーン後の古いリクエストへの対処
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill roblox-networkingインストール後、Claude Code で/roblox-networkingを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlreferences/validation-and-testing.md
詳細
Roblox ネットワーク
サーバーがゲーム状態の権限を持ち、クライアントが入力や意図を提供する、明確なリクエストとレプリケーションの契約を構築します。Roblox のローリングプラットフォーム API を対象としています。このスキルでは、roblox-luau のネットワーク入門よりも踏み込んで解説します。
使用する場面
- Roblox の境界を越える通信を設計、実装、デバッグ、または保護するときに使用します。
- リモートがクライアントの値を信頼している場合、悪意のあるユーザーが任意の Instance を対象にできる場合、メッセージがサービスに大量送信される場合、ストリーミングされたオブジェクトが見つからない場合、またはクライアントとサーバーの状態が一致しない場合に使用します。
使用しない場面: 基本的な Luau やサービスについては roblox-luau を、永続状態については roblox-datastores を使用してください。物理的な所有権の仕組みには roblox-physics も組み合わせてください。
ワークフロー
- 既存のプロトコルを調べます。 すべてのリモートと両方のエンドポイントを探し、方向、送信者、ペイロード、頻度、権限、検証、利用側を記録します。正規のリモートフォルダーを再利用してください。調査を省略したために重複を作らないでください。
- 各メッセージを分類します。 クライアントリクエスト、サーバーの事実、または一時的な見た目用サンプルのいずれかです。利便性ではなく意味に基づいて、信頼性のあるイベント、信頼性のないイベント、リクエスト/レスポンスを選択します。
- ペイロードを最小限にします。 安定した識別子と意図を送信します。サーバーが導き出せる価格、ダメージ、所有権の結果、任意のパス、計算済みの結果は送信しないでください。
- 段階的に検証します。 高コストな処理を行う前に、型/構造/有限値、許可リストに含まれる値、Instance のクラスと祖先、プレイヤーの権限/状態、必要に応じて距離と視線、サーバー側のクールダウン、レート制限を確認します。
- サーバーで適用します。 サーバーが対象を特定し、体力、インベントリ、通貨、クールダウン、進行状況を変更します。クライアント側のチェックは UX を向上させますが、信頼性を保証するものではありません。
- 必要な範囲だけレプリケーションします。 非公開またはローカルな事実には
FireClientを使用し、共有される事実のみをブロードキャストします。クライアントが別個の表示イベントを必要としない限り、レプリケーション済みのプロパティを再度送信しないでください。 - 時間とライフサイクルを考慮します。 リクエストは、死亡、リスポーン、ストリーミングの変更、切断の後に届くことがあります。処理時に現在のキャラクター/状態を取得し、プレイヤーごとのレート制限データをクリーンアップします。
- Server & Clients で検証します。 通常、形式不正、大量送信、範囲外、古いキャラクター、高速なリスポーン、退出、複数プレイヤーの同時操作、個別指定、ブロードキャストの各ケースを試します。サーバーと各クライアントの Output を個別に確認します。
通信方式を選択する
| プリミティブ | 用途 | 使用しない用途 |
|---|---|---|
RemoteEvent | 順序が保証された信頼性のある一方向のリクエスト/事実 | 新しいデータが古いデータに置き換わる連続サンプル |
UnreliableRemoteEvent | 損失や順序の入れ替わりを許容する、一時的な見た目用/連続状態 | 購入、ダメージの決定、インベントリ、一度限りの状態遷移 |
RemoteFunction | 即時の応答が本当に必要な、範囲を限定したクライアントからサーバーへの問い合わせ | サーバーからクライアントへの呼び出し、長時間かかる/所要時間が不確かな処理、通常のコマンド |
サーバーからクライアントを同期的に呼び出してはいけません。クライアントが切断したり、エラーを起こしたり、応答しなかったりする可能性があります。必要に応じて、サーバー側の RemoteEvent:FireClient() と個別の応答イベントを使用してください。
パターン:ゲームプレイの対象を特定する前に検証する
-- 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 <= 0 then return end
if (root.Position - targetRoot.Position).Magnitude > RANGE then return end
if not serverCombatStateAllowsAttack(player, now) then return end
targetHumanoid:TakeDamage(serverDamageFor(player))
end)
Players.PlayerRemoving:Connect(function(player)
lastRequest[player] = nil
end)
これはあくまで簡潔な例です。実際の近接攻撃システムでは、サーバーが把握する攻撃可能時間、視線/形状チェック、チームルール、遅延への対処が必要になる場合があります。距離チェックを 1 つ行うだけで安全になると考えないでください。
パターン:境界でのトークンバケット
type Bucket = {tokens: number, updatedAt: number}
local buckets: {[Player]: Bucket} = {}
local CAPACITY, REFILL_PER_SECOND = 6, 3
local function consume(player: Player, cost: number): boolean
local now = os.clock()
local bucket = buckets[player] or {tokens = CAPACITY, updatedAt = now}
bucket.tokens = math.min(CAPACITY,
bucket.tokens + (now - bucket.updatedAt) * REFILL_PER_SECOND)
bucket.updatedAt = now
if bucket.tokens < cost then buckets[player] = bucket; return false end
bucket.tokens -= cost
buckets[player] = bucket
return true
end
コストはサーバーへの影響に応じて設定します。データストアの呼び出し、クローン作成、レイキャスト、広範囲へのレプリケーションを行う前に、低コストでリクエストを拒否してください。拒否したパケットごとに警告を出すのではなく、不正利用の兆候を集計して記録します。
レプリケーション、ストリーミング、予測
- レプリケーションされたインスタンス/プロパティは、すでに状態チャネルです。リモートは、意図、プライベートな状態、または表示上の合図に使用し、DataModel の無条件な並列コピーには使用しないでください。
- インスタンスのストリーミングでは、有効なサーバー Instance がクライアントに存在しないことがあります。安定した ID を送信して不在を許容し、オプションのストリーミングコンテンツをいつまでも待たないでください。
- 高頻度の見た目だけのデータには
UnreliableRemoteEventを使用できます。配信と順序は保証されないため、各サンプルを自己完結させてください。1000 bytes を超えるペイロードは破棄されます(Studio Output に超過分が表示されます)。RemoteEventとUnreliableRemoteEventには、すべての同種リモートを合算してクライアントあたり約 500 calls/second のスロットルも適用されます。これは、攻撃者より先に正規のプレイヤーが上限に達する値です。 - レイテンシに敏感で、取り消し可能な表示だけを予測してください。クライアントのシーケンス/コマンド ID を含め、サーバーは権威ある状態と確認応答を返し、クライアントは滑らかに修正します。予測によってダメージ、通貨、インベントリ、または進行状況を付与してはいけません。
- ネットワーク所有権は応答性を高めますが、そのクライアントが物理シミュレーションに影響を与えられるようになります。ゲームプレイ上の結果はサーバーで検証してください。所有権は認可ではありません。
よくある失敗
| 症状 | 考えられる原因 | 対処法 |
|---|---|---|
| エクスプロイターがダメージ/価格を選択できる | クライアントからの結果を受け入れている | 意図/ID を送信し、サーバーで導出して適用する |
| 任意のオブジェクトを削除できる | typeof(Instance) しか確認していない | クラス、階層、所有権、状態、許可リストに登録された操作を検証する |
| サーバーがプレイヤーへの処理で停止する | サーバーがクライアントの RemoteFunction を呼び出している | 非同期イベントに置き換える |
| 正規のプレイヤーでスロットルが発生する | フレームごとに信頼性の高いメッセージを送信している | 頻度を下げる、状態レプリケーションを使う、バッチ処理する、または見た目だけのデータには信頼性の低いイベントを使う |
| 古いパケットで新しい効果が取り消される | 順序が保証されないサンプルをコマンドとして扱っている | サンプルを置き換え可能/バージョン管理されたものにする。状態遷移には信頼性の高いイベントを使う |
| リスポーン後にリモートが機能しなくなる | キャラクター/ルートをキャッシュしている | 処理時に現在のキャラクターを取得し、古い状態を拒否する |
| プライベートデータが漏れる | デフォルトで FireAllClients を使用している | FireClient と最小限のペイロードを使用する |
| 距離チェックを回避される | クライアント所有のオブジェクトがターゲットの近くに移動された | 重要なオブジェクトをアンカーする/サーバー所有にし、サーバー側の完全なコンテキストを検証する |
リソース
- ペイロードのルール、Instance/有限値チェック、レプリケーション設計、必須の複数クライアント悪用テストマトリックスについては、
references/validation-and-testing.mdをお読みください。
関連スキル
roblox-luau— 実行場所と RemoteEvent の基本的な仕組み。roblox-characters— リスポーンに対応したキャラクターの取得。roblox-physics— ネットワーク所有権、レイ/オーバーラップ検証、物理的な結果。roblox-studio-workflow— Server & Clients によるテストと Output の確認。
主な参考資料
https://create.roblox.com/docs/scripting/events/remotehttps://create.roblox.com/docs/scripting/security/client-server-boundaryhttps://create.roblox.com/docs/physics/network-ownershiphttps://create.roblox.com/docs/studio/testing-modes