Buffer Based Remote Version 1.0.2
Hi, I’m Flipitagainpls and over the last 2 weeks I’ve been working on a Remote Project, here is what it’s about. Remote is a modular system that handles the firing of remote events and remote functions. Remote Event module uses a runtime-based transferred firing system which allows for a more dynamic and easy fire system, as well as buffing the data. Remote function however uses 5uphi’s remote function method by creating remote functions using remote events since it’s a safer process,
then the data is buffed and transferred between events to process the correct info.
Newest Fixes:
New Version 1.0.2
- Fixed not being able to send more than 1 data.
- Uses @athar_adv new buffer converter: BufferConverter | An easy way to turn anything into a buffer (and back!)
- CFrames Vectors, are all buffed now.
Remote Api:
--Functions:
RemoteEvent.new(eventName: string) - Client
RemoteEvent.new(eventName: string, unreliable: boolean) - Server
RemoteFunction.new(name: string, callbackFn: RBXScriptConnection?) -- Client/Server
--Methods:
remoteEvent:Fire(...) - Client
remoteEvent:Fire(player: Player, ...) - Server
remoteEvent:FireAll(...) - Server
remoteFunction:Invoke(...) -Server/Client -> (any)
Remote Tutorial:
Here is the tutorial:
–[[
---------------------------------------------------- TUTORIAL ----------------------------------------------------
Remote Function: [
---------------------- Client ----------------------
local RemoteFunction = require(ReplicatedStorage.Remote).RemoteFunction
local newFunction = RemoteFunction.new('FirstRemoteFunction')
local info = newFunction:Invoke()
print(info)
---------------------- Server ----------------------
local RemoteFunction = require(ReplicatedStorage.Remote).RemoteFunction
local newFunction = RemoteFunction.new('FirstRemoteFunction', function(player: Player?, ...)
return 'Hello World!'
end)
----- Output -----
Hello World! - Client
]
Remote Event: [
---------------------- Client ----------------------
local RemoteEvent = require(ReplicatedStorage.Remote).RemoteEvent
local newEvent = RemoteFunction.new('RemoteEvent')
newEvent:Fire('Hello World!')
newEvent.OnFired:Connect(function(...)
-- callback for fireclient
end)
---------------------- Server ----------------------
local RemoteEvent = require(ReplicatedStorage.Remote).RemoteEvent
local newEvent = RemoteFunction.new('RemoteEvent')
newEvent.OnFired:Connect(function(player: Player, msg: string?)
print(msg)
newEvent:Fire(player, ...)
newEvent:FireAll(...)
end)
----- Output -----
Hello World! - Server
]
]]
Just Put the Remotes Folder In Replicated Storage And the Remote module wherever you please.
Link: https://create.roblox.com/store/asset/112800451842069/Remote
Source Codes:
Remote Function
--[[
local RemoteFunction , FunctionThreads = {}, {}
---- Services ----
local RunService = game:GetService'RunService'
local ReplicatedStorage = game:GetService'ReplicatedStorage'
---- Modules ----
local Buffer = require(script.Parent.Packages.Buffer)
---- Variables ----
local remotes = ReplicatedStorage.Remotes
---- Functions ----
local function RemoteFunctionErrorHandler(err: string)
local errorExecutionTime = tostring(DateTime.now():FormatLocalTime('LTS', 'en-us'))
error(`\n['RemoteFunction]: \n {err} \nexecuted at {errorExecutionTime}`)
end
local function ReturnProcessedCallback(eventName: string?, exhaustTime: number)
local begin = os.clock()
repeat
task.wait()
local elapsed = (os.clock() - begin)
if elapsed > exhaustTime then
RemoteFunctionErrorHandler('remote function never returned an object')
end
until FunctionThreads[eventName]
return table.unpack(FunctionThreads[eventName])
end
---- Types ----
export type RemoteFunc = {
Invoke: (self: RemoteFunction, any) -> ()
}
---- Construction ----
local constructor = {
new = function(
name: string,
callbackFn: RBXScriptConnection?
)
if RunService:IsClient() then
local self = {}
self.Function = remotes.Functions:FindFirstChild(name) :: RemoteEvent
if self.Function then
self.Function.OnClientEvent:Connect(function(method: string, ...)
if method == 'Client' then
local buffed = Buffer.new(...)
FunctionThreads[name] = buffed
else
local returnedProcessed = callbackFn(table.unpack(...))
if not returnedProcessed then
RemoteFunctionErrorHandler'remote callback does not return at least 1 value'
end
self.Function:FireServer('Server', table.pack(returnedProcessed))
end
end)
function self:Invoke(... : any)
local packed = table.pack(...)
local buffed = Buffer.new(packed)
self.Function:FireServer('Client', buffed)
return ReturnProcessedCallback(name, 4)
end
return self :: RemoteFunc
end
else
local self = {}
if not remotes.Functions:FindFirstChild(name) then
self.Function = Instance.new'RemoteEvent'
self.Function.Name = name
self.Function.Parent = remotes.Functions
else
self.Function = remotes.Functions[name]
end
function self:Invoke(player: Player?, ... : any)
local packed = table.pack(...)
local buffed = Buffer.new(packed)
self.Function:FireClient(player, 'Server', buffed)
return ReturnProcessedCallback(name, 4)
end
self.Function.OnServerEvent:Connect(function(player: Player?, method: string, ...)
if method == 'Client' then
local returnedProcessed = callbackFn(player, table.unpack(...))
if not returnedProcessed then
RemoteFunctionErrorHandler'remote callback does not return at least 1 value'
end
self.Function:FireClient(player, 'Client', table.pack(returnedProcessed))
else
local buffed = Buffer.new(...)
FunctionThreads[name] = buffed
end
end)
return self :: self
end
end,
}
return constructor]]
Remote Event
--[[local RemoteEvent = {}
RemoteEvent.__index = RemoteEvent
---- Services ----
local RunService = game:GetService'RunService'
local ReplicatedStorage = game:GetService'ReplicatedStorage'
---- Variables ----
local utils = script.Parent.Utils
local packages = script.Parent.Packages
local remotes = ReplicatedStorage.Remotes
local Signal = require(packages.Signal)
local Buffer = require(packages.Buffer)
local ClientProcess = require(script.ClientProcess)
local ServerProcess = require(script.ServerProcess)
---- Functions ----
local function RemoteEventErrorHandler(err: string)
local errorExecutionTime = tostring(DateTime.now():FormatLocalTime('LTS', 'en-us'))
error(`\n['RemoteEvent]: \n {err} \nexecuted at {errorExecutionTime}`)
end
local function CreateEventPacket(
eventName: string,
unreliable: boolean?
)
if not remotes.Events.Data:FindFirstChild(eventName) then
local strVal = Instance.new'StringValue'
strVal.Parent = remotes.Events.Data
strVal.Name = eventName
strVal:SetAttribute('Unreliable', unreliable)
end
end
local function GetEventPacket(
eventName: string
)
local rem: StringValue? = remotes.Events.Data:FindFirstChild(eventName)
if rem then
return rem:GetAttribute'Unreliable'
else --@the first param will be unreliable[bool?], if more data is needed to be shared then it will
return nil
end
end
if RunService:IsClient() then
function RemoteEvent.new(eventName: string)
assert(eventName, `given value 'eventName' is missing or nil`)
assert(type(eventName) == 'string', `given value 'eventName' is not a string`)
local unreliable = GetEventPacket(eventName)
if unreliable ~= nil and remotes.Events:FindFirstChild(eventName) then
local self = setmetatable({}, RemoteEvent)
self.unreliable = unreliable
self.remote = remotes.Events[eventName]
self.OnFired = Signal.new()
self.identifier = eventName
self.remote.OnClientEvent:Connect(function(evName: string, ...)
if evName == eventName then self.OnFired:Fire(...) end
end)
return self
else
RemoteEventErrorHandler('missing event (event not created)')
end
end
function RemoteEvent:Fire(...)
local packed = table.pack(...)
local buffed = Buffer.new(packed)
ClientProcess.InsertProcessQueue(self.remote, self.identifier, self.unreliable, buffed)
end
else
function RemoteEvent.new(eventName: string, unreliable: boolean)
assert(eventName, `given value 'eventName' is missing or nil`)
assert(type(eventName) == 'string', `given value 'eventName' is not a string`)
if remotes.Events:FindFirstChild(eventName) then
RemoteEventErrorHandler('EventName already used or created')
else
local self = setmetatable({}, RemoteEvent)
if not unreliable then unreliable = false end
if unreliable then
self.remote = utils.UnreliableEvent:Clone()
self.remote.Parent = remotes.Events
self.remote.Name = eventName
else
self.remote = utils.Event:Clone()
self.remote.Parent = remotes.Events
self.remote.Name = eventName
end
self.OnFired = Signal.new()
self.identifier = eventName
self.unreliable = unreliable
self.remote.OnServerEvent:Connect(function(player, evName: string, ...)
if evName == eventName then self.OnFired:Fire(player, ...) end
end)
CreateEventPacket(eventName, unreliable)
return self
end
end
function RemoteEvent:Fire(player: Player?, ...)
local packed = table.pack(...)
local buffed = Buffer.new(packed)
ServerProcess.InsertProcessQueue(player, self.remote, self.identifier, self.unreliable, buffed)
end
function RemoteEvent:FireAll(... : any?)
local buffed = Buffer.new(table.pack(...))
ServerProcess.InsertProcessQueue(nil, self.remote, self.identifier, self.unreliable, buffed)
end
end
return RemoteEvent]]
If there is anything you would like me to add to the api (that you think is useful) I will. Also, whoever decides to use this please give me feedback and do benchmarks to see what the performance looks like. So far I’ve compared it to roblox’s default remote event and its given me good results, so please feel free to show me your results.