Skip to content

About

remote warpper

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Remote

A thin, typed wrapper around RemoteEvent, UnreliableRemoteEvent, and RemoteFunction for Roblox — one module for both server and client.

No middleware, no serialization layer, no magic. Just less boilerplate: instances are created lazily on the server, waited for on the client, cached by name, and every method delegates directly to the underlying signal, so there is zero per-fire overhead beyond a single method lookup.

Features

  • One API on both sides — require the same module from a Script or a LocalScript; it detects the runtime and returns the right implementation.
  • Lazy creation — the server creates the Remotes folder and instances on first use. No manual setup in ReplicatedStorage.
  • Cached by name — calling Remote.Event("Hit") from ten different scripts returns the same object with no repeated FindFirstChild/WaitForChild cost.
  • UnreliableRemoteEvent support — first-class support for high-frequency, loss-tolerant data (positions, aim, cosmetic effects).
  • Class-safe names — requesting a name that already exists as a different remote class throws a clear error instead of silently returning the wrong instance.
  • Extra fire helpers — FireAllExcept and FireClients for common broadcast patterns.
  • --!strict typed — exported types for annotating your own code (Event, ServerEvent, ClientEvent, RemoteFn, ServerFunction, ClientFunction).

Installation

Roblox Studio: create a ModuleScript named Remote in ReplicatedStorage (or anywhere both sides can require it) and paste in Remote.luau.

Rojo: drop Remote.luau into your shared source folder, e.g.

src/
  shared/
    Remote.luau   →  ReplicatedStorage/Shared/Remote

Quick start

Server

local Remote = require(ReplicatedStorage.Shared.Remote)

local DamageDealt = Remote.Event("DamageDealt")

DamageDealt:Connect(function(player, targetId, amount)
	-- Always validate client input — arguments are untyped and untrusted
	if typeof(targetId) ~= "number" or typeof(amount) ~= "number" then
		return
	end
	-- ... apply damage on the server's terms
end)

DamageDealt:FireAllClients(targetId, actualDamage)

Client

local Remote = require(ReplicatedStorage.Shared.Remote)

local DamageDealt = Remote.Event("DamageDealt")

DamageDealt:Connect(function(targetId, amount)
	showDamageNumber(targetId, amount)
end)

DamageDealt:FireServer(targetId, amount)

High-frequency data — use an unreliable event and throttle to a fixed tick:

local Movement = Remote.UnreliableEvent("Movement")
-- Fire at 10–20 Hz, never per frame; payloads must stay ≤ 900 bytes

Request/response

-- Server
local GetProfile = Remote.Function("GetProfile")
GetProfile.OnInvoke = function(player)
	return profiles[player.UserId]
end

-- Client
local profile = Remote.Function("GetProfile"):Invoke()

API

Constructors

Function Returns Backing instance
Remote.Event(name) Event RemoteEvent
Remote.UnreliableEvent(name) Event UnreliableRemoteEvent
Remote.Function(name) RemoteFn RemoteFunction

All constructors are idempotent: the first call creates (server) or waits for (client) the instance; later calls return the cached object. Names are shared across all three kinds — reusing a name with a different constructor throws.

Event methods

Method Side Description
:Connect(callback) both Connects to OnServerEvent (server, callback receives player first) or OnClientEvent (client). Returns RBXScriptConnection.
:Once(callback) both Like Connect, auto-disconnects after the first fire.
:Wait() both Yields until the next fire and returns its arguments.
:FireServer(...) client Fires to the server.
:FireClient(player, ...) server Fires to one player.
:FireAllClients(...) server Fires to everyone.
:FireAllExcept(excluded, ...) server Fires to everyone except one player.
:FireClients(players, ...) server Fires to a specific list of players.

Calling a method on the wrong side (e.g. FireServer on the server) errors at runtime; the shared Event type intentionally exposes both sides so one module works everywhere. Annotate with ServerEvent/ClientEvent if you want the type checker to narrow it.

Function members

Member Side Description
.OnInvoke = fn both Assigns the handler (OnServerInvoke / OnClientInvoke under the hood). Server handlers receive player as the first argument.
:Invoke(...) client Calls the server handler and yields for the result.
:Invoke(player, ...) server Calls InvokeClient — avoid this (see warnings).

Warnings and best practices

  • Avoid server → client Invoke. InvokeClient yields the server thread forever if the client never responds (disconnects, hangs, or an exploiter deliberately stalls). Prefer a pair of events for round-trips; if you must use it, wrap it in task.spawn + pcall.
  • Validate everything on the server. This wrapper passes arguments through untouched (...any). Exploiters can fire any remote with any payload — always check types and ranges, and rate-limit sensitive handlers.
  • Don't fire per frame. Batch small frequent messages and flush on a fixed tick; use UnreliableEvent for loss-tolerant streams.
  • Client requires can yield. On the client, constructors use WaitForChild, so requiring an event the server never creates yields indefinitely (Roblox prints an "Infinite yield possible" warning after 5 seconds to help you spot it).
  • One name, one kind. Event, UnreliableEvent, and Function share a namespace; the module errors loudly on a class mismatch rather than handing you the wrong instance.

License

MIT — see LICENSE.

About

remote warpper

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages