This commit is contained in:
EternityDev 2024-09-27 11:10:12 +07:00
parent 064075fbd9
commit dbed984eea
16 changed files with 209 additions and 202 deletions

View file

@ -1,5 +1,4 @@
--!strict --!strict
--!native
--!optimize 2 --!optimize 2
local Logger = {} local Logger = {}
local Logs: { local Logs: {
@ -31,4 +30,8 @@ function Logger.read(Identifier: string)
return Logs[Identifier] return Logs[Identifier]
end end
return Logger function Logger.clear(Identifier: string)
Logs[Identifier] = nil
end
return Logger :: typeof(Logger)

View file

@ -84,7 +84,7 @@ end
function ClientProcess.add(Identifier: any, originId: string, conf: Type.ClientConf) function ClientProcess.add(Identifier: any, originId: string, conf: Type.ClientConf)
if not table.find(registeredIdentifier, Identifier) then if not table.find(registeredIdentifier, Identifier) then
table.insert(registeredIdentifier, Identifier) table.insert(registeredIdentifier, Identifier)
if conf.logging then if conf.logging then
ClientProcess.logger(Identifier, conf.logging.store, conf.logging.opt) ClientProcess.logger(Identifier, conf.logging.store, conf.logging.opt)
end end
@ -122,6 +122,22 @@ function ClientProcess.add(Identifier: any, originId: string, conf: Type.ClientC
end end
end end
function ClientProcess.remove(Identifier: string)
if not table.find(registeredIdentifier, Identifier) then return end
table.remove(registeredIdentifier, table.find(registeredIdentifier, Identifier))
clientQueue[Identifier] = nil
unreliableClientQueue[Identifier] = nil
clientRequestQueue[Identifier] = nil
clientCallback[Identifier] = nil
clientRatelimit[Identifier] = nil
queueOutRequest[1][Identifier] = nil
queueOutRequest[2][Identifier] = nil
queueInRequest[1][Identifier] = nil
queueInRequest[2][Identifier] = nil
queueIn[Identifier] = nil
Logger.clear(Identifier)
end
function ClientProcess.logger(Identifier: string, store: boolean, log: boolean) function ClientProcess.logger(Identifier: string, store: boolean, log: boolean)
logger[Identifier] = store logger[Identifier] = store
Logger.write(Identifier, `state: change -> {log == true and "enabled" or "disabled"} logger.`, log) Logger.write(Identifier, `state: change -> {log == true and "enabled" or "disabled"} logger.`, log)
@ -147,55 +163,49 @@ end
function ClientProcess.start() function ClientProcess.start()
debug.setmemorycategory("Warp") debug.setmemorycategory("Warp")
local clock_limit = 1/60
local past_clock = os.clock()
RunService.PostSimulation:Connect(function() RunService.PostSimulation:Connect(function()
if (os.clock()-past_clock) >= (clock_limit - 0.006) then -- less potential to skip frames -- Unreliable
past_clock = os.clock() for Identifier: string, data: any in unreliableClientQueue do
-- Unreliable if #data == 0 then continue end
for Identifier: string, data: any in unreliableClientQueue do if clientRatelimit[Identifier](#data) then
if #data == 0 then continue end UnreliableEvent:FireServer(Buffer.revert(Identifier), data)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#data} data.`)
end
end
unreliableClientQueue[Identifier] = nil
end
-- Reliable
for Identifier: string, data: any in clientQueue do
if #data > 0 then
if clientRatelimit[Identifier](#data) then if clientRatelimit[Identifier](#data) then
UnreliableEvent:FireServer(Buffer.revert(Identifier), data) ReliableEvent:FireServer(Buffer.revert(Identifier), data)
if logger[Identifier] then if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#data} data.`) task.defer(Logger.write, Identifier, `state: out -> reliable -> {#data} data.`)
end end
end end
unreliableClientQueue[Identifier] = nil clientQueue[Identifier] = nil
end
-- Reliable
for Identifier: string, data: any in clientQueue do
if #data > 0 then
if clientRatelimit[Identifier](#data) then
ReliableEvent:FireServer(Buffer.revert(Identifier), data)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> reliable -> {#data} data.`)
end
end
clientQueue[Identifier] = nil
end
end
-- Sent new invokes
for Identifier: string, requestsData in queueOutRequest[1] do
if #requestsData == 0 then continue end
RequestEvent:FireServer(Buffer.revert(Identifier), "\1", requestsData)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> request -> {#requestsData} data.`)
end
queueOutRequest[1][Identifier] = nil
end
-- Sent returning invokes
for Identifier: string, toReturnDatas in queueOutRequest[2] do
if #toReturnDatas == 0 then continue end
RequestEvent:FireServer(Buffer.revert(Identifier), "\0", toReturnDatas)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> return request -> {#toReturnDatas} data.`)
end
queueOutRequest[2][Identifier] = nil
end end
end end
-- Sent new invokes
for Identifier: string, requestsData in queueOutRequest[1] do
if #requestsData == 0 then continue end
RequestEvent:FireServer(Buffer.revert(Identifier), "\1", requestsData)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> request -> {#requestsData} data.`)
end
queueOutRequest[1][Identifier] = nil
end
-- Sent returning invokes
for Identifier: string, toReturnDatas in queueOutRequest[2] do
if #toReturnDatas == 0 then continue end
RequestEvent:FireServer(Buffer.revert(Identifier), "\0", toReturnDatas)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> return request -> {#toReturnDatas} data.`)
end
queueOutRequest[2][Identifier] = nil
end
for _, Identifier: string in registeredIdentifier do for _, Identifier: string in registeredIdentifier do
if clientRequestQueue[Identifier] then if clientRequestQueue[Identifier] then
for _, requestData in clientRequestQueue[Identifier] do for _, requestData in clientRequestQueue[Identifier] do
@ -207,11 +217,11 @@ function ClientProcess.start()
requestData[3] = nil requestData[3] = nil
end end
end end
-- Unreliable & Reliable -- Unreliable & Reliable
local callback = clientCallback[Identifier] or nil local callback = clientCallback[Identifier] or nil
if not callback then continue end if not callback then continue end
if queueIn[Identifier] then if queueIn[Identifier] then
for _, packedDatas: any in queueIn[Identifier] do for _, packedDatas: any in queueIn[Identifier] do
if #packedDatas == 0 then continue end if #packedDatas == 0 then continue end
@ -223,7 +233,7 @@ function ClientProcess.start()
end end
queueIn[Identifier] = nil queueIn[Identifier] = nil
end end
-- Return Invoke -- Return Invoke
if queueInRequest[1][Identifier] then if queueInRequest[1][Identifier] then
for _, packetDatas: any in queueInRequest[1][Identifier] do for _, packetDatas: any in queueInRequest[1][Identifier] do
@ -247,7 +257,7 @@ function ClientProcess.start()
end end
queueInRequest[1][Identifier] = nil queueInRequest[1][Identifier] = nil
end end
-- Call to Invoke -- Call to Invoke
if queueInRequest[2][Identifier] then if queueInRequest[2][Identifier] then
if clientRequestQueue[Identifier] then if clientRequestQueue[Identifier] then

View file

@ -13,16 +13,14 @@ local Assert = require(Util.Assert)
local Key = require(Util.Key) local Key = require(Util.Key)
local Serdes = require(Util.Serdes) local Serdes = require(Util.Serdes)
local Buffer = require(Util.Buffer) local Buffer = require(Util.Buffer)
local Middleware = require(Util.Middleware)
function Client.new(Identifier: string, conf: Type.ClientConf?) function Client.new(Identifier: string, conf: Type.ClientConf?)
local self = setmetatable({}, Client) local self = setmetatable({}, Client)
self._buffer = Buffer.new() self._buffer = Buffer.new()
self._buffer:wu8(Serdes(Identifier, conf and conf.yieldWait)) self._buffer:wu8(Serdes.increment(Identifier, conf and conf.yieldWait))
self.id = Buffer.convert(self._buffer:build()) self.id = Buffer.convert(self._buffer:build())
self.fn = {} self.fn = {}
self.middleware = {}
self._conf = table.freeze(conf or {}) self._conf = table.freeze(conf or {})
self.IsConnected = false self.IsConnected = false
@ -45,39 +43,23 @@ function Client:Invoke(timeout: number, ...: any): any
return ClientProcess.insertRequest(self.id, timeout, ...) return ClientProcess.insertRequest(self.id, timeout, ...)
end end
function Client:Connect(callback: (args: any) -> ()) function Client:Connect(callback: (args: any) -> ()): string
local key = tostring(Key()) local key = tostring(Key())
local _middleware = Middleware(key)
table.insert(self.fn, key) table.insert(self.fn, key)
self.middleware[key] = _middleware
self.IsConnected = #self.fn > 0 self.IsConnected = #self.fn > 0
ClientProcess.addCallback(self.id, key, function(...) ClientProcess.addCallback(self.id, key, callback)
if _middleware.bridge(...) then return key
return callback(...)
end
return nil
end)
return _middleware
end end
function Client:Once(callback: (args: any) -> ()) function Client:Once(callback: (args: any) -> ()): string
local key = tostring(Key()) local key = tostring(Key())
local _middleware = Middleware(key)
table.insert(self.fn, key) table.insert(self.fn, key)
self.middleware[key] = _middleware
self.IsConnected = #self.fn > 0 self.IsConnected = #self.fn > 0
ClientProcess.addCallback(self.id, key, function(...) ClientProcess.addCallback(self.id, key, function(...: any?)
self:Disconnect(key) self:Disconnect(key)
if _middleware.bridge(...) then task.spawn(callback, ...)
return callback(...)
end
return nil
end) end)
return _middleware return key
end end
function Client:Wait() function Client:Wait()
@ -99,14 +81,14 @@ function Client:Disconnect(key: string)
ClientProcess.removeCallback(self.id, key) ClientProcess.removeCallback(self.id, key)
table.remove(self.fn, table.find(self.fn, key)) table.remove(self.fn, table.find(self.fn, key))
self.IsConnected = #self.fn > 0 self.IsConnected = #self.fn > 0
if self.middleware[key] then
self.middleware[key]:destroy()
self.middleware[key] = nil
end
end end
function Client:Destroy() function Client:Destroy()
self:DisconnectAll() self:DisconnectAll()
self._buffer:remove()
ClientProcess.remove(self.id)
Serdes.decrement()
table.clear(self)
setmetatable(self, nil) setmetatable(self, nil)
end end

View file

@ -1,5 +1,4 @@
--!strict --!strict
--!native
--!optimize 2 --!optimize 2
local RunService = game:GetService("RunService") local RunService = game:GetService("RunService")
local Type = require(script.Parent.Type) local Type = require(script.Parent.Type)

View file

@ -13,16 +13,14 @@ local Assert = require(Util.Assert)
local Key = require(Util.Key) local Key = require(Util.Key)
local Serdes = require(Util.Serdes) local Serdes = require(Util.Serdes)
local Buffer = require(Util.Buffer) local Buffer = require(Util.Buffer)
local Middleware = require(Util.Middleware)
function Server.new(Identifier: string, conf: Type.ServerConf?) function Server.new(Identifier: string, conf: Type.ServerConf?)
local self = setmetatable({}, Server) local self = setmetatable({}, Server)
self._buffer = Buffer.new() self._buffer = Buffer.new()
self._buffer:wu8(Serdes(Identifier)) self._buffer:wu8(Serdes.increment(Identifier))
self.id = Buffer.convert(self._buffer:build()) self.id = Buffer.convert(self._buffer:build())
self.fn = {} self.fn = {}
self.middleware = {}
self._conf = table.freeze(conf or {}) self._conf = table.freeze(conf or {})
self.IsConnected = false self.IsConnected = false
@ -65,39 +63,23 @@ function Server:Invoke(timeout: number, player: Player, ...: any): any
return ServerProcess.insertRequest(self.id, timeout, player, ...) return ServerProcess.insertRequest(self.id, timeout, player, ...)
end end
function Server:Connect(callback: (plyer: Player, args: any) -> ()) function Server:Connect(callback: (plyer: Player, args: any) -> ()): string
local key = tostring(Key()) local key = tostring(Key())
local _middleware = Middleware(key)
table.insert(self.fn, key) table.insert(self.fn, key)
self.middleware[key] = _middleware ServerProcess.addCallback(self.id, key, callback)
self.IsConnected = #self.fn > 0 self.IsConnected = #self.fn > 0
ServerProcess.addCallback(self.id, key, function(...) return key
if _middleware.bridge(...) then
return callback(...)
end
return nil
end)
return _middleware
end end
function Server:Once(callback: (plyer: Player, args: any) -> ()) function Server:Once(callback: (plyer: Player, args: any) -> ()): string
local key = tostring(Key()) local key = tostring(Key())
local _middleware = Middleware(key)
table.insert(self.fn, key) table.insert(self.fn, key)
self.middleware[key] = _middleware
self.IsConnected = #self.fn > 0 self.IsConnected = #self.fn > 0
ServerProcess.addCallback(self.id, key, function(...) ServerProcess.addCallback(self.id, key, function(player: Player, ...: any?)
self:Disconnect(key) self:Disconnect(key)
if _middleware.bridge(...) then task.spawn(callback, player, ...)
return callback(...)
end
return nil
end) end)
return _middleware return key
end end
function Server:Wait() function Server:Wait()
@ -119,15 +101,15 @@ function Server:Disconnect(key: string): boolean
ServerProcess.removeCallback(self.id, key) ServerProcess.removeCallback(self.id, key)
table.remove(self.fn, table.find(self.fn, key)) table.remove(self.fn, table.find(self.fn, key))
self.IsConnected = #self.fn > 0 self.IsConnected = #self.fn > 0
if self.middleware[key] then
self.middleware[key]:destroy()
self.middleware[key] = nil
end
return table.find(self.fn, key) == nil return table.find(self.fn, key) == nil
end end
function Server:Destroy() function Server:Destroy()
self:DisconnectAll() self:DisconnectAll()
self._buffer:remove()
ServerProcess.remove(self.id)
Serdes.decrement()
table.clear(self)
setmetatable(self, nil) setmetatable(self, nil)
end end

View file

@ -1,5 +1,4 @@
--!strict --!strict
--!native
--!optimize 2 --!optimize 2
local Logger = {} local Logger = {}
local Logs: { local Logs: {
@ -31,4 +30,8 @@ function Logger.read(Identifier: string)
return Logs[Identifier] return Logs[Identifier]
end end
return Logger function Logger.clear(Identifier: string)
Logs[Identifier] = nil
end
return Logger :: typeof(Logger)

View file

@ -142,9 +142,9 @@ end
function ServerProcess.add(Identifier: string, originId: string, conf: Type.ServerConf) function ServerProcess.add(Identifier: string, originId: string, conf: Type.ServerConf)
if not table.find(registeredIdentifier, Identifier) then if not table.find(registeredIdentifier, Identifier) then
table.insert(registeredIdentifier, Identifier) table.insert(registeredIdentifier, Identifier)
RateLimit.create(originId, conf.rateLimit and conf.rateLimit.maxEntrance or 200, conf.rateLimit and conf.rateLimit.interval or 2) RateLimit.create(originId, conf.rateLimit and conf.rateLimit.maxEntrance or 200, conf.rateLimit and conf.rateLimit.interval or 2)
if conf.logging then if conf.logging then
ServerProcess.logger(Identifier, conf.logging.store, conf.logging.opt) ServerProcess.logger(Identifier, conf.logging.store, conf.logging.opt)
end end
@ -183,6 +183,21 @@ function ServerProcess.add(Identifier: string, originId: string, conf: Type.Serv
end end
end end
function ServerProcess.remove(Identifier: string)
if not table.find(registeredIdentifier, Identifier) then return end
table.remove(registeredIdentifier, table.find(registeredIdentifier, Identifier))
serverQueue[Identifier] = nil
serverRequestQueue[Identifier] = nil
serverCallback[Identifier] = nil
unreliableServerQueue[Identifier] = nil
queueIn[Identifier] = nil
queueInRequest[1][Identifier] = nil
queueInRequest[2][Identifier] = nil
queueOutRequest[1][Identifier] = nil
queueOutRequest[2][Identifier] = nil
Logger.clear(Identifier)
end
function ServerProcess.logger(Identifier: string, store: boolean, log: boolean) function ServerProcess.logger(Identifier: string, store: boolean, log: boolean)
logger[Identifier] = store logger[Identifier] = store
Logger.write(Identifier, `state: change -> {log == true and "enabled" or "disabled"} logger.`, log) Logger.write(Identifier, `state: change -> {log == true and "enabled" or "disabled"} logger.`, log)
@ -208,60 +223,54 @@ end
function ServerProcess.start() function ServerProcess.start()
debug.setmemorycategory("Warp") debug.setmemorycategory("Warp")
local clock_limit = 1/60
local past_clock = os.clock()
RunService.PostSimulation:Connect(function() RunService.PostSimulation:Connect(function()
if (os.clock()-past_clock) >= (clock_limit - 0.006) then -- less potential to skip frames -- Unreliable
past_clock = os.clock() for Identifier: string, players in unreliableServerQueue do
-- Unreliable for player: Player, content: any in players do
for Identifier: string, players in unreliableServerQueue do if #content == 0 then continue end
for player: Player, content: any in players do UnreliableEvent:FireClient(player, Buffer.revert(Identifier), content)
if #content == 0 then continue end if logger[Identifier] then
UnreliableEvent:FireClient(player, Buffer.revert(Identifier), content) task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#content} data.`)
end
unreliableServerQueue[Identifier][player] = nil
end
unreliableServerQueue[Identifier] = nil
end
-- Reliable
for Identifier: string, contents: { [Player]: { any } } in serverQueue do
for player, content: any in contents do
if #content > 0 and queueOut[player] then
ReliableEvent:FireClient(player, Buffer.revert(Identifier), content)
end
serverQueue[Identifier][player] = nil
end
serverQueue[Identifier] = nil
end
-- Sent new invokes
for Identifier: string, contents in queueOutRequest[1] do
for player: Player, requestsData: any in contents do
if #requestsData > 0 then
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\1", requestsData)
if logger[Identifier] then if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#content} data.`) task.defer(Logger.write, Identifier, `state: out -> request -> {#requestsData} data.`)
end end
unreliableServerQueue[Identifier][player] = nil
end end
unreliableServerQueue[Identifier] = nil queueOutRequest[1][Identifier][player] = nil
end end
-- Reliable queueOutRequest[1][Identifier] = nil
for Identifier: string, contents: { [Player]: { any } } in serverQueue do end
for player, content: any in contents do -- Sent returning invokes
if #content > 0 and queueOut[player] then for Identifier: string, contents in queueOutRequest[2] do
ReliableEvent:FireClient(player, Buffer.revert(Identifier), content) for player: Player, toReturnDatas: any in contents do
if #toReturnDatas > 0 then
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\0", toReturnDatas)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> return request -> {#toReturnDatas} data.`)
end end
serverQueue[Identifier][player] = nil
end end
serverQueue[Identifier] = nil queueOutRequest[2][Identifier][player] = nil
end
-- Sent new invokes
for Identifier: string, contents in queueOutRequest[1] do
for player: Player, requestsData: any in contents do
if #requestsData > 0 then
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\1", requestsData)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> request -> {#requestsData} data.`)
end
end
queueOutRequest[1][Identifier][player] = nil
end
queueOutRequest[1][Identifier] = nil
end
-- Sent returning invokes
for Identifier: string, contents in queueOutRequest[2] do
for player: Player, toReturnDatas: any in contents do
if #toReturnDatas > 0 then
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\0", toReturnDatas)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: out -> return request -> {#toReturnDatas} data.`)
end
end
queueOutRequest[2][Identifier][player] = nil
end
queueOutRequest[2][Identifier] = nil
end end
queueOutRequest[2][Identifier] = nil
end end
for _, Identifier: string in registeredIdentifier do for _, Identifier: string in registeredIdentifier do
@ -281,10 +290,10 @@ function ServerProcess.start()
end end
end end
end end
local callback = serverCallback[Identifier] or nil local callback = serverCallback[Identifier] or nil
if not callback then continue end if not callback then continue end
-- Unreliable & Reliable -- Unreliable & Reliable
for player, content in queueIn[Identifier] do for player, content in queueIn[Identifier] do
if not callback then break end if not callback then break end
@ -299,7 +308,7 @@ function ServerProcess.start()
end end
queueIn[Identifier][player] = nil queueIn[Identifier][player] = nil
end end
-- Return Invoke -- Return Invoke
for player, content in queueInRequest[1][Identifier] do for player, content in queueInRequest[1][Identifier] do
if not callback then break end if not callback then break end
@ -328,7 +337,7 @@ function ServerProcess.start()
end end
queueInRequest[1][Identifier][player] = nil queueInRequest[1][Identifier][player] = nil
end end
-- Call to Invoke -- Call to Invoke
for player, content in queueInRequest[2][Identifier] do for player, content in queueInRequest[2][Identifier] do
if not callback then break end if not callback then break end

View file

@ -12,6 +12,7 @@ function Dedicated.new(signal: any, handler: (...any) -> ())
end end
function Dedicated:Disconnect() function Dedicated:Disconnect()
table.clear(self)
setmetatable(self, nil) setmetatable(self, nil)
end end

View file

@ -3,6 +3,7 @@
--!optimize 2 --!optimize 2
local Signal = {} local Signal = {}
Signal.__index = Signal Signal.__index = Signal
Signal.ClassName = "Signal"
local DedicatedSignal = require(script.Dedicated) local DedicatedSignal = require(script.Dedicated)
@ -22,15 +23,15 @@ function Signal.new(Identifier: string)
return Signals[Identifier] return Signals[Identifier]
end end
function Signal:Connect(fn: (...any) -> ()): string function Signal:Connect(fn: (...any) -> (), optKey: string?): string
local key = tostring(Key()) local key: typeof(Signal) = optKey or tostring(Key()) :: any
self[key] = DedicatedSignal(self, fn) self[key] = DedicatedSignal(self, fn)
return key return key :: any
end end
function Signal:Once(fn: (...any) -> ()): string function Signal:Once(fn: (...any) -> ()): string
local key: string local key: string
key = self:Connect(function(...) key = self:Connect(function(...: any)
self:Disconnect(key) self:Disconnect(key)
task.spawn(fn, ...) task.spawn(fn, ...)
end) end)
@ -38,19 +39,17 @@ function Signal:Once(fn: (...any) -> ()): string
end end
function Signal:Disconnect(key: string) function Signal:Disconnect(key: string)
if not self[key] then return end
self[key]:Disconnect() self[key]:Disconnect()
self[key] = nil self[key] = nil
end end
function Signal:DisconnectAll(): () function Signal:DisconnectAll(): ()
for _, handle in self do
handle:Disconnect()
end
table.clear(self) table.clear(self)
end end
function Signal:Wait(): number function Signal:Wait(): number
local thread, t = coroutine.running(), os.clock() local t, thread = os.clock(), coroutine.running()
self:Once(function() self:Once(function()
task.spawn(thread, os.clock()-t) task.spawn(thread, os.clock()-t)
end) end)
@ -88,12 +87,6 @@ end
function Signal:Destroy(): () function Signal:Destroy(): ()
self:DisconnectAll() self:DisconnectAll()
for idx: string, signal in Signals do
if self :: any == signal then
Signals[idx] = nil
break
end
end
setmetatable(self, nil) setmetatable(self, nil)
end end

View file

@ -1,6 +1,6 @@
--!strict --!strict
--!native --!native
--!optimize 2 --!optimize 2
return function(condition: (any), errorMessage: string?): () return function(condition: (any), errorMessage: string, level: number?): ()
if not (condition) then error(`Warp: {errorMessage}`, 2) end if not (condition) then error(`Warp: {errorMessage}`, level or 2) end
end end

View file

@ -128,7 +128,7 @@ function DedicatedBuffer.new()
end end
function DedicatedBuffer.remove(self: any) function DedicatedBuffer.remove(self: any)
self:flush() table.clear(self)
setmetatable(self, nil) setmetatable(self, nil)
end end

View file

@ -1,6 +1,5 @@
--!strict --!strict
--!native
--!optimize 2 --!optimize 2
return function(): number? return function(): number?
return tonumber(string.sub(tostring(Random.new():NextNumber()), 3, 6)) -- 4 digits return tonumber(tostring(Random.new():NextNumber()):sub(3, 7)) -- 4-5 digits
end end

View file

@ -1,5 +1,4 @@
--!strict --!strict
--!native
--!optimize 2 --!optimize 2
local RateLimit = {} local RateLimit = {}

View file

@ -1,18 +1,19 @@
--!strict --!strict
--!native
--!optimize 2 --!optimize 2
local SerDes = {}
local RunService = game:GetService("RunService") local RunService = game:GetService("RunService")
local SerInt = 0 local SerInt = 0
local Event = require(script.Parent.Parent.Event).Reliable local Event = require(script.Parent.Parent.Event).Reliable
local Assert = require(script.Parent.Assert) local Assert = require(script.Parent.Assert)
return function(Identifier: string, timeout: number?): number function SerDes.increment(Identifier: string, timeout: number?): number
Assert(typeof(Identifier) == "string", "Identifier must be a string type.") Assert(typeof(Identifier) == "string", "Identifier must be a string type.")
Assert(SerInt < 255, "reached max 255 identifiers.")
if RunService:IsServer() then if RunService:IsServer() then
Assert(SerInt < 255, "reached max 255 identifiers.")
if not Event:GetAttribute(Identifier) then if not Event:GetAttribute(Identifier) then
SerInt += 1 SerInt += 1
Event:SetAttribute(`{SerInt}`, Identifier)
Event:SetAttribute(Identifier, SerInt) Event:SetAttribute(Identifier, SerInt)
--Event:SetAttribute(Identifier, string.pack("I1", SerInt)) -- I1 -> 255 max, I2 -> ~ 6.5e4 max. (SerInt), removed/disabled for buffer migration. --Event:SetAttribute(Identifier, string.pack("I1", SerInt)) -- I1 -> 255 max, I2 -> ~ 6.5e4 max. (SerInt), removed/disabled for buffer migration.
end end
@ -20,11 +21,11 @@ return function(Identifier: string, timeout: number?): number
local yieldThread: thread = coroutine.running() local yieldThread: thread = coroutine.running()
local cancel = task.delay(timeout or 10, function() -- yield cancelation (timerout) local cancel = task.delay(timeout or 10, function() -- yield cancelation (timerout)
task.spawn(yieldThread, nil) task.spawn(yieldThread, nil)
error(`Serdes: {Identifier} is taking too long to retrieve, seems like not replicated on server.`, 2) error(`Serdes: {Identifier} is taking too long to retrieve, seems like it's not replicated on server.`, 2)
end) end)
task.spawn(function() task.spawn(function()
while coroutine.status(cancel) ~= "dead" and task.wait(0.5) do -- let it loop for yields! while coroutine.status(cancel) ~= "dead" and task.wait(0.5) do -- let it loop for yields!
if (Event:GetAttribute(Identifier)) then if Event:GetAttribute(Identifier) then
task.cancel(cancel) task.cancel(cancel)
task.spawn(yieldThread, Event:GetAttribute(Identifier)) task.spawn(yieldThread, Event:GetAttribute(Identifier))
break break
@ -35,3 +36,15 @@ return function(Identifier: string, timeout: number?): number
end end
return Event:GetAttribute(Identifier) return Event:GetAttribute(Identifier)
end end
function SerDes.decrement()
if not RunService:IsServer() or SerInt <= 0 then return end
local Identifier = Event:GetAttribute(`{SerInt}`)
if not Identifier then return end
Event:SetAttribute(`{Identifier}`, nil)
Event:SetAttribute(`{SerInt}`, nil)
SerInt -= 1
Identifier = nil
end
return SerDes :: typeof(SerDes)

View file

@ -1,13 +1,20 @@
--!native --!native
--!strict --!strict
--!optimize 2 --!optimize 2
local thread: thread? = nil local thread: thread?
local threads: {
thread
} = {}
local function passer(fn, ...): () local function passer<T...>(func: (T...) -> (), ...: T...): ()
local hold = thread local HoldThread: thread = thread :: thread
thread = nil thread = nil
fn(...) func(...)
thread = hold if not thread then
thread = HoldThread
return
end
table.insert(threads, HoldThread)
end end
local function yield(): never local function yield(): never
@ -16,15 +23,22 @@ local function yield(): never
end end
end end
if not thread then local function createThread(): ()
thread = coroutine.create(yield) local newThread: thread = coroutine.create(yield)
coroutine.resume(thread :: any, thread) coroutine.resume(newThread, newThread)
table.insert(threads, newThread)
end end
return function(fn: (...any) -> (...any?), ...: any): () for _=1,5 do
createThread()
end
return function<T...>(func: (T...) -> (), ...: T...): ()
if not thread then if not thread then
thread = coroutine.create(yield) if #threads == 0 then
coroutine.resume(thread :: any, thread) createThread()
end
thread = table.remove(threads, 1)
end end
task.spawn(thread :: thread, fn, ...) task.spawn(thread :: thread, func, ...)
end end

View file

@ -1,5 +1,5 @@
-- Warp Library (@Eternity_Devs) -- Warp Library (@Eternity_Devs)
-- version 1.0.12 -- version 1.0.13
--!strict --!strict
--!native --!native
--!optimize 2 --!optimize 2