Hello devs, I want to know how can I improve my code with new features or optimization, I’m stuck with this one right now:
--!strict
--!optimize 2
--Client
local Client = {}
Client.__index = Client
Client.ClientQueue = {}
--Services
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--Strings
local ScriptRequireRunContext = if RunService:IsClient() then "Client" else "Server"
--Instances
local Util = script:WaitForChild("Util", 5)
local Communication = script.Parent:WaitForChild("Comunication", 5)
local Remote = Communication:WaitForChild("Server-ClientCommunication", 5)
--Modules
local WaitForPlayerToReplicateOnServer = require(Util.WaitForPlayerToReplicateOnServer)
local SendPlayerToServer = require(Util.SendPlayerToServer)
local EventServerClientCommunicationRemote = require(Util.EventServerClientCommunicationRemote)
local SetLock = require(Util.SetLock)
local UnSetLock = require(Util.UnSetLock)
local HasServerBeenReplicated = require(Util.HasServerBeenReplicated)
local HandlerRequests = require(Util.HandleRequests)
local HashGenerator = require(Util.HashGenerator)
local Signal = require(ReplicatedStorage.Signal)
--Numbers
local WaitTimeout = 15
--Booleans
local hasServerBeenReplicated = false
--Main Functions
--Creates a new queue for the player (<em>if it don't exist yet</em>) and a new identifier element with a reliable and unreliable queue inside (<em>if it they don't exist yet</em>) and return a <em>self</em> element (<em>or a nil one depending on the value of <strong>HasServerBeenReplicated</strong>, a boolean that decides it</em>).
--@param player - A player object to pass in the function.
--@param identifier - A string to define the identifier.
function Client.new(player: Player, identifier: string, encryptRequests: boolean?)
if not Client.ClientQueue[player.UserId] then
Client.ClientQueue[player.UserId] = {}
end
if Client.ClientQueue[player.UserId][identifier] then return end
SendPlayerToServer(player, Remote)
SetLock(player, Client.ClientQueue, identifier)
WaitForPlayerToReplicateOnServer(WaitTimeout)
if hasServerBeenReplicated then
Remote:Destroy()
UnSetLock(player, Client.ClientQueue, identifier)
Client.ClientQueue[player.UserId][identifier].Events["OnReceive"] = Signal.new()
Client.ClientQueue[player.UserId][identifier].Events["OnSend"] = Signal.new()
table.freeze(Client.ClientQueue[player.UserId][identifier].Events)
else
return nil
end
local self = {}
self._queue = Client.ClientQueue[player.UserId]
self._queueIdentifier = self._queue[identifier]
self._eventReceiveQueue = self._queueIdentifier.Events["OnReceive"]
self._eventSendQueue = self._queueIdentifier.Events["OnSend"]
self._remotes = player:FindFirstChild("RemoteFolder") :: Folder
self._reliable = self._remotes:FindFirstChild("Reliable") :: RemoteEvent
self._unrealiable = self._remotes:FindFirstChild("Unreliable") :: RemoteEvent
task.spawn(HandlerRequests, self._reliable, player, identifier, self._queueIdentifier, self._eventReceiveQueue, WaitTimeout, encryptRequests, HashGenerator)
task.spawn(HandlerRequests, self._unrealiable, player, identifier, self._queueIdentifier, self._eventReceiveQueue, WaitTimeout, encryptRequests, HashGenerator)
--Sends a request to the server with a ReliableRemote (<em>if reliable is true</em>) else with a UnreliableRemote, using the identifier and the <strong>...</strong> param.
--@param reliable - A boolean to specify the type of the remote.
--@param ... - The data to send to the server.
function self:send(reliable: boolean, ...: any)
local remote: any = if reliable then self._reliable else self._unreliable
remote:FireServer(identifier, ...)
local function AddTimeoutRequest(req: any, tbl: {any})
table.insert(tbl, req)
local index = #tbl
for i = 1, WaitTimeout do
tbl[index] = nil
end
end
local queue = if remote:IsA("RemoteEvent") then "ReliableQueue" else "UnreliableQueue"
task.spawn(AddTimeoutRequest, if encryptRequests then HashGenerator(tostring({...})) else {...}, self._queueIdentifier[queue].Out)
self._eventSendQueue:Fire(...)
end
--Connects the event.
--@param fn - A function to connect to the event when its fired.
--@param ... - A (<em>optional</em>) param to specify the data to connect to <strong>fn</strong>.
function self:onReceived(fn: (any) -> any, ...: any?)
return self._eventReceiveQueue:Connect(fn, ...)
end
--Waits until the event is fired.
function self:waitUntilReceived()
return self._eventReceiveQueue:Wait()
end
--Connects the event once.
--@param fn - A function to connect to the event when its fired.
--@param ... - A (<em>optional</em>) param to specify the data to connect to <strong>fn</strong>
function self:onReceivedOnce(fn: (any) -> any, ...: any?)
return self._eventReceiveQueue:Once(fn, ...)
end
--Disconnects all the connections from the event.
function self:onReceivedDisconnectAll()
return self._eventReceiveQueue:DisconnectAll()
end
--Connects the event.
--@param fn - A function to connect to the event when its fired.
--@param ... - A (<em>optional</em>) param to specify the data to connect to <strong>fn</strong>
function self:onSend(fn: (any) -> any, ...: any?)
return self._eventSendQueue:Connect(fn, ...)
end
--Waits until the event is fired.
function self:waitUntilSend()
return self._eventSendQueue:Wait()
end
--Connects to the event once.
--@param fn - A function to connect to the event when its fired.
--@param ... - A (<em>optional</em>) param to specify the data to connect to <strong>fn</strong>
function self:onSendOnce(fn: (any) -> any, ...: any?)
return self._eventSendQueue:Once(fn, ...)
end
--Disconnects all the connections from the event.
function self:onSenddisconnectAll()
return self._eventSendQueue:DisconnectAll()
end
--Destroys the <em>self</em> element.
function self:destroy()
table.clear(self)
Client.ClientQueue[player.UserId] = nil
end
return self
end
--Finds if the player has been queued.
--@param player - A player object.
function Client.find(player: Player)
return Client.ClientQueue[player.UserId]
end
--Finds if the player has been queued and if the identifier queue has been initialized.
--@param player - A player object.
--@param identifier - A string to define the identifier queue.
function Client.findIdentifier(player: Player, identifier: string)
return Client.find(player)[identifier]
end
--Waits until the queue has been initialized (<strong>yields</strong>), could return nil too.
--@param fn - A function to wait its return.
--@param ... - A (<em>optional</em>) param to specify the data that gets send to the <strong>fn</strong>.
function Client.waitUntilIntialized(fn: (any) -> any, ...: any?)
local ret = nil
local t1
task.spawn(function(...)
t1 = os.clock()
ret = fn(...)
end, ...)
while not ret do
if ret then break end
if (os.clock() - t1) >= WaitTimeout then break end
task.wait()
end
return ret
end
--Events
Remote.OnClientEvent:Connect(function(player: Player, response: any)
local event = EventServerClientCommunicationRemote(player, response)
hasServerBeenReplicated = if typeof(event) == "boolean" then event else false
if not hasServerBeenReplicated then
Client.ClientQueue[player.UserId] = nil
end
end)
return Client
To anyone asking this is a Client Module of a Replication System I’m making.
Thanks for the time let me know your ideas!