This commit is contained in:
EternityDev 2024-05-19 13:17:07 +07:00
parent 44fa07df85
commit aa693aee4f
10 changed files with 284 additions and 208 deletions

BIN
Warp.rbxm

Binary file not shown.

View file

@ -13,8 +13,10 @@ When creating a event on Server, you can add second argument (optional) as table
-- Server -- Server
-- Let's make the event have ratelimit with max 50 entrance for 2 seconds. -- Let's make the event have ratelimit with max 50 entrance for 2 seconds.
local Remote = Warp.Server("Remote1", { local Remote = Warp.Server("Remote1", {
rateLimit = {
maxEntrance = 50, -- maximum 50 fires. maxEntrance = 50, -- maximum 50 fires.
interval = 2, -- 2 seconds interval = 2, -- 2 seconds
}
}) })
-- Now the Event RateLimit is configured, and ready to use. -- Now the Event RateLimit is configured, and ready to use.
-- No need anything to adds on client side. -- No need anything to adds on client side.

View file

@ -36,12 +36,16 @@ Create new Warp events with array.
```lua [Example] ```lua [Example]
local Events = Warp.fromServerArray({ local Events = Warp.fromServerArray({
["Remote1"] = { ["Remote1"] = {
rateLimit = {
maxEntrance: 50, maxEntrance: 50,
interval: 1, interval: 1,
}
}, -- with rateLimit configuration }, -- with rateLimit configuration
"Remote2", -- without rateLimit configuration "Remote2", -- without rateLimit configuration
["Remote3"] = { ["Remote3"] = {
rateLimit = {
maxEntrance: 10, maxEntrance: 10,
}
}, -- with rateLimit configuration }, -- with rateLimit configuration
}) })

View file

@ -102,7 +102,23 @@ Signal1:DisconnectAll()
## `:Fire` ## `:Fire`
Fire the signal. Fire the signal (Immediate)
::: code-group
```lua [Variable]
(
...: any
)
```
```lua [Example]
Signal1:Fire("Hello World!")
```
:::
## `:DeferFire`
Fire the signal (Deferred)
::: code-group ::: code-group
```lua [Variable] ```lua [Variable]
@ -122,7 +138,7 @@ This uses `pcall`, which means it never error (safe-mode, sacrificed debugging),
## `:FireTo` ## `:FireTo`
Fire to other signal, this also use `:Fire`. Fire to other signal, this uses `:Fire`.
::: code-group ::: code-group
```lua [Variable] ```lua [Variable]

View file

@ -8,7 +8,7 @@
::: code-group ::: code-group
```toml [wally.toml] ```toml [wally.toml]
[dependencies] [dependencies]
warp = "imezx/warp@1.0.5" warp = "imezx/warp@1.0.11"
``` ```
3. Run `wally install` in command. 3. Run `wally install` in command.

View file

@ -19,6 +19,7 @@ local clientQueue: Type.QueueMap = {}
local unreliableClientQueue: Type.QueueMap = {} local unreliableClientQueue: Type.QueueMap = {}
local clientCallback: Type.CallbackMap = {} local clientCallback: Type.CallbackMap = {}
local clientRequestQueue: Type.QueueMap = {} local clientRequestQueue: Type.QueueMap = {}
local registeredIdentifier: { string } = {}
local queueIn: { local queueIn: {
[string]: {any} [string]: {any}
@ -37,11 +38,6 @@ local queueOutRequest: {
} }
} }
} = {} } = {}
local incoming_cache: {
[string]: {
any
}
} = {}
local logger: { local logger: {
[string]: boolean [string]: boolean
} = {} } = {}
@ -86,7 +82,9 @@ function ClientProcess.insertRequest(Identifier: string, timeout: number, ...: a
end end
function ClientProcess.add(Identifier: any, originId: string, conf: Type.ClientConf) function ClientProcess.add(Identifier: any, originId: string, conf: Type.ClientConf)
if not clientQueue[Identifier] then if not table.find(registeredIdentifier, Identifier) then
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
@ -149,7 +147,13 @@ 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
past_clock = os.clock()
-- Unreliable
for Identifier: string, data: any in unreliableClientQueue do for Identifier: string, data: any in unreliableClientQueue do
if #data == 0 then continue end if #data == 0 then continue end
if clientRatelimit[Identifier](#data) then if clientRatelimit[Identifier](#data) then
@ -160,8 +164,8 @@ function ClientProcess.start()
end end
unreliableClientQueue[Identifier] = nil unreliableClientQueue[Identifier] = nil
end end
-- Reliable
for Identifier: string, data: any in clientQueue do for Identifier: string, data: any in clientQueue do
local callback = clientCallback[Identifier] or nil
if #data > 0 then if #data > 0 then
if clientRatelimit[Identifier](#data) then if clientRatelimit[Identifier](#data) then
ReliableEvent:FireServer(Buffer.revert(Identifier), data) ReliableEvent:FireServer(Buffer.revert(Identifier), data)
@ -171,6 +175,28 @@ function ClientProcess.start()
end end
clientQueue[Identifier] = nil clientQueue[Identifier] = nil
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
end
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
if not requestData[3] then continue end if not requestData[3] then continue end
@ -179,20 +205,12 @@ function ClientProcess.start()
end end
table.insert(queueOutRequest[1][Identifier], { requestData[1], requestData[3] }) table.insert(queueOutRequest[1][Identifier], { requestData[1], requestData[3] })
end end
clientRequestQueue[Identifier] = nil
end
if callback then
if incoming_cache[Identifier] then
for _, packet in incoming_cache[Identifier] do
if #packet == 0 then continue end
for _, fn: any in callback do
for i=1,#packet do
Spawn(fn, table.unpack(packet[i] or {}))
end
end
end
incoming_cache[Identifier] = nil
end end
-- Unreliable & Reliable
local callback = clientCallback[Identifier] or nil
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
@ -204,25 +222,32 @@ function ClientProcess.start()
end end
queueIn[Identifier] = nil queueIn[Identifier] = nil
end end
-- 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
if #packetDatas == 0 then continue end if #packetDatas == 0 then continue end
for _, fn: any in callback do for _, fn: any in callback do
for i=1,#packetDatas do for i=1,#packetDatas do
local packetData = packetDatas[i] if not packetDatas[i] then continue end
if not packetData then continue end local packetData1 = packetDatas[i][1]
local packetData2 = packetDatas[i][2]
Spawn(function() Spawn(function()
local requestReturn = { fn(table.unpack(packetData[2])) } local requestReturn = { fn(table.unpack(packetData1)) }
if not queueOutRequest[2][Identifier] then if not queueOutRequest[2][Identifier] then
queueOutRequest[2][Identifier] = {} queueOutRequest[2][Identifier] = {}
end end
table.insert(queueOutRequest[2][Identifier], { packetData[1], requestReturn }) table.insert(queueOutRequest[2][Identifier], { packetData2, requestReturn })
packetData1 = nil
packetData2 = nil
end) end)
end end
end end
end end
queueInRequest[1][Identifier] = nil queueInRequest[1][Identifier] = nil
end end
-- Call to Invoke
if queueInRequest[2][Identifier] then if queueInRequest[2][Identifier] then
if clientRequestQueue[Identifier] then if clientRequestQueue[Identifier] then
for _, packetDatas: any in queueInRequest[2][Identifier] do for _, packetDatas: any in queueInRequest[2][Identifier] do
@ -243,23 +268,6 @@ function ClientProcess.start()
queueInRequest[2][Identifier] = nil queueInRequest[2][Identifier] = nil
end end
end end
end
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
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)
local function onClientNetworkReceive(Identifier: any, data: any) local function onClientNetworkReceive(Identifier: any, data: any)
if not Identifier or not data then return end if not Identifier or not data then return end
@ -267,16 +275,6 @@ function ClientProcess.start()
if not queueIn[Identifier] then if not queueIn[Identifier] then
queueIn[Identifier] = {} queueIn[Identifier] = {}
end end
if not clientCallback[Identifier] then
if not incoming_cache[Identifier] then
incoming_cache[Identifier] = {}
end
table.insert(incoming_cache[Identifier], data)
if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: cache -> net -> {#data} data.`)
end
return
end
table.insert(queueIn[Identifier], data) table.insert(queueIn[Identifier], data)
if logger[Identifier] then if logger[Identifier] then
task.defer(Logger.write, Identifier, `state: in -> net -> {#data} data.`) task.defer(Logger.write, Identifier, `state: in -> net -> {#data} data.`)

View file

@ -72,12 +72,21 @@ local function initializeEachPlayer(player: Player)
if not queueOut[player][Identifier] then if not queueOut[player][Identifier] then
queueOut[player][Identifier] = {} queueOut[player][Identifier] = {}
end end
if not serverRequestQueue[Identifier] then
serverRequestQueue[Identifier] = {}
end
if not serverRequestQueue[Identifier][player] then if not serverRequestQueue[Identifier][player] then
serverRequestQueue[Identifier][player] = {} serverRequestQueue[Identifier][player] = {}
end end
if not queueIn[Identifier][player] then if not queueIn[Identifier][player] then
queueIn[Identifier][player] = {} queueIn[Identifier][player] = {}
end end
if not queueOutRequest[1][Identifier] then
queueOutRequest[1][Identifier] = {}
end
if not queueOutRequest[2][Identifier] then
queueOutRequest[2][Identifier] = {}
end
if not queueInRequest[1][Identifier][player] then if not queueInRequest[1][Identifier][player] then
queueInRequest[1][Identifier][player] = {} queueInRequest[1][Identifier][player] = {}
queueInRequest[2][Identifier][player] = {} queueInRequest[2][Identifier][player] = {}
@ -93,12 +102,18 @@ Players.PlayerAdded:Connect(initializeEachPlayer)
function ServerProcess.insertQueue(Identifier: string, reliable: boolean, player: Player, ...: any) function ServerProcess.insertQueue(Identifier: string, reliable: boolean, player: Player, ...: any)
if not reliable then if not reliable then
if not unreliableServerQueue[Identifier] then
unreliableServerQueue[Identifier] = {}
end
if not unreliableServerQueue[Identifier][player] then if not unreliableServerQueue[Identifier][player] then
unreliableServerQueue[Identifier][player] = {} unreliableServerQueue[Identifier][player] = {}
end end
table.insert(unreliableServerQueue[Identifier][player], { ... }) table.insert(unreliableServerQueue[Identifier][player], { ... })
return return
end end
if not serverQueue[Identifier] then
serverQueue[Identifier] = {}
end
if not serverQueue[Identifier][player] then if not serverQueue[Identifier][player] then
serverQueue[Identifier][player] = {} serverQueue[Identifier][player] = {}
end end
@ -106,12 +121,12 @@ function ServerProcess.insertQueue(Identifier: string, reliable: boolean, player
end end
function ServerProcess.insertRequest(Identifier: string, timeout: number, player: Player, ...: any) function ServerProcess.insertRequest(Identifier: string, timeout: number, player: Player, ...: any)
if not serverQueue[Identifier][player] then
serverQueue[Identifier][player] = {}
end
if not serverRequestQueue[Identifier] then if not serverRequestQueue[Identifier] then
serverRequestQueue[Identifier] = {} serverRequestQueue[Identifier] = {}
end end
if not serverRequestQueue[Identifier][player] then
serverRequestQueue[Identifier][player] = {}
end
local yieldThread: thread, start = coroutine.running(), os.clock() local yieldThread: thread, start = coroutine.running(), os.clock()
local cancel = task.delay(timeout, function() local cancel = task.delay(timeout, function()
task.spawn(yieldThread, nil) task.spawn(yieldThread, nil)
@ -127,7 +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
@ -191,7 +208,13 @@ 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
past_clock = os.clock()
-- Unreliable
for Identifier: string, players in unreliableServerQueue do for Identifier: string, players in unreliableServerQueue do
for player: Player, content: any in players do for player: Player, content: any in players do
if #content == 0 then continue end if #content == 0 then continue end
@ -201,11 +224,21 @@ function ServerProcess.start()
end end
unreliableServerQueue[Identifier][player] = nil unreliableServerQueue[Identifier][player] = nil
end end
unreliableServerQueue[Identifier] = nil
end end
-- Reliable
for Identifier: string, contents: { [Player]: { any } } in serverQueue do for Identifier: string, contents: { [Player]: { any } } in serverQueue do
for player, content: any in contents do
for player: Player, requestsData: any in queueOutRequest[1][Identifier] 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 if #requestsData > 0 then
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\1", requestsData) RequestEvent:FireClient(player, Buffer.revert(Identifier), "\1", requestsData)
if logger[Identifier] then if logger[Identifier] then
@ -214,8 +247,11 @@ function ServerProcess.start()
end end
queueOutRequest[1][Identifier][player] = nil queueOutRequest[1][Identifier][player] = nil
end end
queueOutRequest[1][Identifier] = nil
for player: Player, toReturnDatas: any in queueOutRequest[2][Identifier] do end
-- Sent returning invokes
for Identifier: string, contents in queueOutRequest[2] do
for player: Player, toReturnDatas: any in contents do
if #toReturnDatas > 0 then if #toReturnDatas > 0 then
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\0", toReturnDatas) RequestEvent:FireClient(player, Buffer.revert(Identifier), "\0", toReturnDatas)
if logger[Identifier] then if logger[Identifier] then
@ -224,66 +260,79 @@ function ServerProcess.start()
end end
queueOutRequest[2][Identifier][player] = nil queueOutRequest[2][Identifier][player] = nil
end end
queueOutRequest[2][Identifier] = nil
local callback = serverCallback[Identifier] or nil end
for player, content: any in contents do
if #content > 0 and queueOut[player] then
ReliableEvent:FireClient(player, Buffer.revert(Identifier), content)
end end
serverQueue[Identifier][player] = nil
if serverRequestQueue[Identifier][player] then for _, Identifier: string in registeredIdentifier do
for _, requestData in serverRequestQueue[Identifier][player] do if serverRequestQueue[Identifier] then
for player, content in serverRequestQueue[Identifier] do
for _, requestData in content do
if not requestData[3] then continue end if not requestData[3] then continue end
if not queueOutRequest[1][Identifier] then
queueOutRequest[1][Identifier] = {}
end
if not queueOutRequest[1][Identifier][player] then if not queueOutRequest[1][Identifier][player] then
queueOutRequest[1][Identifier][player] = {} queueOutRequest[1][Identifier][player] = {}
end end
table.insert(queueOutRequest[1][Identifier][player], { requestData[1], requestData[3] }) table.insert(queueOutRequest[1][Identifier][player], { requestData[1], requestData[3] })
end end
serverRequestQueue[Identifier][player] = nil end
end end
if callback then local callback = serverCallback[Identifier] or nil
local requestIn1: any = queueInRequest[1][Identifier][player] if not callback then continue end
local requestIn2: any = queueInRequest[2][Identifier][player]
local incoming: any = queueIn[Identifier][player]
if incoming then -- Unreliable & Reliable
for _, packedDatas: any in incoming do for player, content in queueIn[Identifier] do
if #packedDatas == 0 then continue end if not callback then break end
for _, incoming in content do
if not callback then break end
if #incoming == 0 then continue end
for _, fn: any in callback do for _, fn: any in callback do
for i=1,#packedDatas do for i=1,#incoming do
Spawn(fn, player, table.unpack(packedDatas[i] or {})) Spawn(fn, player, table.unpack(incoming[i] or {}))
end end
end end
end end
incoming = nil
queueIn[Identifier][player] = nil queueIn[Identifier][player] = nil
end end
if requestIn1 then
for _, packetDatas: any in requestIn1 do -- Return Invoke
for player, content in queueInRequest[1][Identifier] do
if not callback then break end
for _, packetDatas in content do
if not callback then break end
if #packetDatas == 0 then continue end if #packetDatas == 0 then continue end
for _, fn: any in callback do for _, fn: any in callback do
for i=1,#packetDatas do for i=1,#packetDatas do
local packetData = packetDatas[i] if not packetDatas[i] then continue end
if not packetData then continue end local packetData1 = packetDatas[i][1]
local packetData2 = packetDatas[i][2]
Spawn(function() Spawn(function()
local requestReturn = { fn(player, table.unpack(packetData[2])) } local requestReturn = { fn(player, table.unpack(packetData2)) }
local state = queueOutRequest[2][Identifier][player] if not queueOutRequest[2][Identifier] then
queueOutRequest[2][Identifier] = {}
end
if not queueOutRequest[2][Identifier][player] then if not queueOutRequest[2][Identifier][player] then
queueOutRequest[2][Identifier][player] = {} queueOutRequest[2][Identifier][player] = {}
end end
table.insert(queueOutRequest[2][Identifier][player], { packetData[1], requestReturn }) table.insert(queueOutRequest[2][Identifier][player], { packetData1, requestReturn })
packetData1 = nil
packetData2 = nil
end) end)
end end
end end
end end
requestIn1 = nil
queueInRequest[1][Identifier][player] = nil queueInRequest[1][Identifier][player] = nil
end end
if requestIn2 then
for _, packetDatas: any in requestIn2 do -- Call to Invoke
for player, content in queueInRequest[2][Identifier] do
if not callback then break end
for _, packetDatas in content do
for _, packetData in packetDatas do for _, packetData in packetDatas do
if not callback then break end
if #packetData == 1 then continue end if #packetData == 1 then continue end
local data = serverRequestQueue[Identifier][player] local data = serverRequestQueue[Identifier][player]
for i=1,#data do for i=1,#data do
@ -297,10 +346,8 @@ function ServerProcess.start()
end end
end end
end end
requestIn2 = nil
queueInRequest[2][Identifier][player] = nil queueInRequest[2][Identifier][player] = nil
end serverRequestQueue[Identifier] = nil
end
end end
end end
end) end)
@ -330,6 +377,9 @@ function ServerProcess.start()
queueInRequest[1][Identifier][player] = {} queueInRequest[1][Identifier][player] = {}
queueInRequest[2][Identifier][player] = {} queueInRequest[2][Identifier][player] = {}
end end
if not serverQueue[Identifier] then
serverQueue[Identifier] = {}
end
if not serverQueue[Identifier][player] then if not serverQueue[Identifier][player] then
serverQueue[Identifier][player] = {} serverQueue[Identifier][player] = {}
end end

View file

@ -53,6 +53,12 @@ function Signal:Wait(): number
return coroutine.yield() return coroutine.yield()
end end
function Signal:DeferFire(...: any): ()
for _, handle in self do
task.defer(handle.fn, ...)
end
end
function Signal:Fire(...: any): () function Signal:Fire(...: any): ()
for _, handle in self do for _, handle in self do
task.spawn(handle.fn, ...) task.spawn(handle.fn, ...)

View file

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

View file

@ -1,6 +1,6 @@
[package] [package]
name = "imezx/warp" name = "imezx/warp"
version = "1.0.10" version = "1.0.11"
registry = "https://github.com/UpliftGames/wally-index" registry = "https://github.com/UpliftGames/wally-index"
realm = "shared" realm = "shared"
license = "MIT" license = "MIT"