From aa693aee4f5fd7dc497103f576106c2964a5d213 Mon Sep 17 00:00:00 2001 From: EternityDev Date: Sun, 19 May 2024 13:17:07 +0700 Subject: [PATCH] v1.0.11 --- Warp.rbxm | Bin 14986 -> 15261 bytes docs/api/1.0/ratelimit.md | 6 +- docs/api/1.0/server.md | 10 +- docs/api/1.0/signal.md | 20 +- docs/guide/installation.md | 2 +- src/Index/Client/ClientProcess/init.luau | 196 +++++++++--------- src/Index/Server/ServerProcess/init.luau | 248 ++++++++++++++--------- src/Index/Signal/init.luau | 6 + src/init.luau | 2 +- wally.toml | 2 +- 10 files changed, 284 insertions(+), 208 deletions(-) diff --git a/Warp.rbxm b/Warp.rbxm index 6c9c3356e8ae660a9cb99d7b72c849098c428124..a33fd2eefb51734854eb3e55ce6e719e5f1ecee8 100644 GIT binary patch delta 10538 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

{`oyJmKiD@f2O#`O3+=Q6f8!dOrC8)}N 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 tJsvA{omZrTW)b(;LtuT unreliable -> {#data} data.`) - end - end - unreliableClientQueue[Identifier] = nil - end - for Identifier: string, data: any in clientQueue do - local callback = clientCallback[Identifier] or nil - if #data > 0 then + 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 + if #data == 0 then continue end if clientRatelimit[Identifier](#data) then - ReliableEvent:FireServer(Buffer.revert(Identifier), data) + UnreliableEvent:FireServer(Buffer.revert(Identifier), data) if logger[Identifier] then - task.defer(Logger.write, Identifier, `state: out -> reliable -> {#data} data.`) + task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#data} data.`) end end - clientQueue[Identifier] = nil + unreliableClientQueue[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 + + for _, Identifier: string in registeredIdentifier do if clientRequestQueue[Identifier] then for _, requestData in clientRequestQueue[Identifier] do if not requestData[3] then continue end @@ -179,87 +205,69 @@ function ClientProcess.start() end table.insert(queueOutRequest[1][Identifier], { requestData[1], requestData[3] }) 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 + + -- Unreliable & Reliable + local callback = clientCallback[Identifier] or nil + if not callback then continue end + + if queueIn[Identifier] then + for _, packedDatas: any in queueIn[Identifier] do + if #packedDatas == 0 then continue end + for _, fn: any in callback do + for i=1,#packedDatas do + Spawn(fn, table.unpack(packedDatas[i] or {})) end end - incoming_cache[Identifier] = nil end - if queueIn[Identifier] then - for _, packedDatas: any in queueIn[Identifier] do - if #packedDatas == 0 then continue end - for _, fn: any in callback do - for i=1,#packedDatas do - Spawn(fn, table.unpack(packedDatas[i] or {})) - end + queueIn[Identifier] = nil + end + + -- Return Invoke + if queueInRequest[1][Identifier] then + for _, packetDatas: any in queueInRequest[1][Identifier] do + if #packetDatas == 0 then continue end + for _, fn: any in callback do + for i=1,#packetDatas do + if not packetDatas[i] then continue end + local packetData1 = packetDatas[i][1] + local packetData2 = packetDatas[i][2] + Spawn(function() + local requestReturn = { fn(table.unpack(packetData1)) } + if not queueOutRequest[2][Identifier] then + queueOutRequest[2][Identifier] = {} + end + table.insert(queueOutRequest[2][Identifier], { packetData2, requestReturn }) + packetData1 = nil + packetData2 = nil + end) end end - queueIn[Identifier] = nil end - if queueInRequest[1][Identifier] then - for _, packetDatas: any in queueInRequest[1][Identifier] do - if #packetDatas == 0 then continue end - for _, fn: any in callback do - for i=1,#packetDatas do - local packetData = packetDatas[i] - if not packetData then continue end - Spawn(function() - local requestReturn = { fn(table.unpack(packetData[2])) } - if not queueOutRequest[2][Identifier] then - queueOutRequest[2][Identifier] = {} - end - table.insert(queueOutRequest[2][Identifier], { packetData[1], requestReturn }) - end) - end - end - end - queueInRequest[1][Identifier] = nil - end - if queueInRequest[2][Identifier] then - if clientRequestQueue[Identifier] then - for _, packetDatas: any in queueInRequest[2][Identifier] do - for _, packetData in packetDatas do - if #packetData == 1 then continue end - for y=1,#clientRequestQueue[Identifier] do - local clientRequest = clientRequestQueue[Identifier][y] - if not clientRequest then continue end - if clientRequest[1] == packetData[1] then - Spawn(clientRequest[2], table.unpack(packetData[2])) - table.remove(clientRequestQueue[Identifier], y) - break - end + queueInRequest[1][Identifier] = nil + end + + -- Call to Invoke + if queueInRequest[2][Identifier] then + if clientRequestQueue[Identifier] then + for _, packetDatas: any in queueInRequest[2][Identifier] do + for _, packetData in packetDatas do + if #packetData == 1 then continue end + for y=1,#clientRequestQueue[Identifier] do + local clientRequest = clientRequestQueue[Identifier][y] + if not clientRequest then continue end + if clientRequest[1] == packetData[1] then + Spawn(clientRequest[2], table.unpack(packetData[2])) + table.remove(clientRequestQueue[Identifier], y) + break end end end end - queueInRequest[2][Identifier] = nil end + queueInRequest[2][Identifier] = nil 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) local function onClientNetworkReceive(Identifier: any, data: any) if not Identifier or not data then return end @@ -267,16 +275,6 @@ function ClientProcess.start() if not queueIn[Identifier] then queueIn[Identifier] = {} 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) if logger[Identifier] then task.defer(Logger.write, Identifier, `state: in -> net -> {#data} data.`) diff --git a/src/Index/Server/ServerProcess/init.luau b/src/Index/Server/ServerProcess/init.luau index 20f0481..b1940d8 100644 --- a/src/Index/Server/ServerProcess/init.luau +++ b/src/Index/Server/ServerProcess/init.luau @@ -72,12 +72,21 @@ local function initializeEachPlayer(player: Player) if not queueOut[player][Identifier] then queueOut[player][Identifier] = {} end + if not serverRequestQueue[Identifier] then + serverRequestQueue[Identifier] = {} + end if not serverRequestQueue[Identifier][player] then serverRequestQueue[Identifier][player] = {} end if not queueIn[Identifier][player] then queueIn[Identifier][player] = {} 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 queueInRequest[1][Identifier][player] = {} queueInRequest[2][Identifier][player] = {} @@ -93,12 +102,18 @@ Players.PlayerAdded:Connect(initializeEachPlayer) function ServerProcess.insertQueue(Identifier: string, reliable: boolean, player: Player, ...: any) if not reliable then + if not unreliableServerQueue[Identifier] then + unreliableServerQueue[Identifier] = {} + end if not unreliableServerQueue[Identifier][player] then unreliableServerQueue[Identifier][player] = {} end table.insert(unreliableServerQueue[Identifier][player], { ... }) return end + if not serverQueue[Identifier] then + serverQueue[Identifier] = {} + end if not serverQueue[Identifier][player] then serverQueue[Identifier][player] = {} end @@ -106,12 +121,12 @@ function ServerProcess.insertQueue(Identifier: string, reliable: boolean, player end 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 serverRequestQueue[Identifier] = {} end + if not serverRequestQueue[Identifier][player] then + serverRequestQueue[Identifier][player] = {} + end local yieldThread: thread, start = coroutine.running(), os.clock() local cancel = task.delay(timeout, function() task.spawn(yieldThread, nil) @@ -127,7 +142,9 @@ end function ServerProcess.add(Identifier: string, originId: string, conf: Type.ServerConf) if not table.find(registeredIdentifier, Identifier) then table.insert(registeredIdentifier, Identifier) + RateLimit.create(originId, conf.rateLimit and conf.rateLimit.maxEntrance or 200, conf.rateLimit and conf.rateLimit.interval or 2) + if conf.logging then ServerProcess.logger(Identifier, conf.logging.store, conf.logging.opt) end @@ -191,116 +208,146 @@ end function ServerProcess.start() debug.setmemorycategory("Warp") + local clock_limit = 1/60 + local past_clock = os.clock() + RunService.PostSimulation:Connect(function() - for Identifier: string, players in unreliableServerQueue do - for player: Player, content: any in players do - if #content == 0 then continue end - UnreliableEvent:FireClient(player, Buffer.revert(Identifier), content) - if logger[Identifier] then - task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#content} data.`) + 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 player: Player, content: any in players do + if #content == 0 then continue end + UnreliableEvent:FireClient(player, Buffer.revert(Identifier), content) + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#content} data.`) + end + unreliableServerQueue[Identifier][player] = nil end - unreliableServerQueue[Identifier][player] = nil + 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 + 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 - - for Identifier: string, contents: { [Player]: { any } } in serverQueue do - - for player: Player, requestsData: any in queueOutRequest[1][Identifier] 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 - - for player: Player, toReturnDatas: any in queueOutRequest[2][Identifier] 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 - - local callback = serverCallback[Identifier] or nil - 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 - - if serverRequestQueue[Identifier][player] then - for _, requestData in serverRequestQueue[Identifier][player] do + + for _, Identifier: string in registeredIdentifier 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 queueOutRequest[1][Identifier] then + queueOutRequest[1][Identifier] = {} + end if not queueOutRequest[1][Identifier][player] then queueOutRequest[1][Identifier][player] = {} end table.insert(queueOutRequest[1][Identifier][player], { requestData[1], requestData[3] }) end - serverRequestQueue[Identifier][player] = nil end - - if callback then - local requestIn1: any = queueInRequest[1][Identifier][player] - local requestIn2: any = queueInRequest[2][Identifier][player] - local incoming: any = queueIn[Identifier][player] - - if incoming then - for _, packedDatas: any in incoming do - if #packedDatas == 0 then continue end - for _, fn: any in callback do - for i=1,#packedDatas do - Spawn(fn, player, table.unpack(packedDatas[i] or {})) - end - end + end + + local callback = serverCallback[Identifier] or nil + if not callback then continue end + + -- Unreliable & Reliable + for player, content in queueIn[Identifier] do + 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 i=1,#incoming do + Spawn(fn, player, table.unpack(incoming[i] or {})) end - incoming = nil - queueIn[Identifier][player] = nil - end - if requestIn1 then - for _, packetDatas: any in requestIn1 do - if #packetDatas == 0 then continue end - for _, fn: any in callback do - for i=1,#packetDatas do - local packetData = packetDatas[i] - if not packetData then continue end - Spawn(function() - local requestReturn = { fn(player, table.unpack(packetData[2])) } - local state = queueOutRequest[2][Identifier][player] - if not queueOutRequest[2][Identifier][player] then - queueOutRequest[2][Identifier][player] = {} - end - table.insert(queueOutRequest[2][Identifier][player], { packetData[1], requestReturn }) - end) - end - end - end - requestIn1 = nil - queueInRequest[1][Identifier][player] = nil - end - if requestIn2 then - for _, packetDatas: any in requestIn2 do - for _, packetData in packetDatas do - if #packetData == 1 then continue end - local data = serverRequestQueue[Identifier][player] - for i=1,#data do - local serverRequest = data[i] - if not serverRequest then continue end - if serverRequest[1] == packetData[1] then - Spawn(serverRequest[2], table.unpack(packetData[2])) - table.remove(data, i) - break - end - end - end - end - requestIn2 = nil - queueInRequest[2][Identifier][player] = nil end end + queueIn[Identifier][player] = nil + end + + -- 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 + for _, fn: any in callback do + for i=1,#packetDatas do + if not packetDatas[i] then continue end + local packetData1 = packetDatas[i][1] + local packetData2 = packetDatas[i][2] + Spawn(function() + local requestReturn = { fn(player, table.unpack(packetData2)) } + if not queueOutRequest[2][Identifier] then + queueOutRequest[2][Identifier] = {} + end + if not queueOutRequest[2][Identifier][player] then + queueOutRequest[2][Identifier][player] = {} + end + table.insert(queueOutRequest[2][Identifier][player], { packetData1, requestReturn }) + packetData1 = nil + packetData2 = nil + end) + end + end + end + queueInRequest[1][Identifier][player] = nil + end + + -- 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 + if not callback then break end + if #packetData == 1 then continue end + local data = serverRequestQueue[Identifier][player] + for i=1,#data do + local serverRequest = data[i] + if not serverRequest then continue end + if serverRequest[1] == packetData[1] then + Spawn(serverRequest[2], table.unpack(packetData[2])) + table.remove(data, i) + break + end + end + end + end + queueInRequest[2][Identifier][player] = nil + serverRequestQueue[Identifier] = nil end end end) @@ -330,6 +377,9 @@ function ServerProcess.start() queueInRequest[1][Identifier][player] = {} queueInRequest[2][Identifier][player] = {} end + if not serverQueue[Identifier] then + serverQueue[Identifier] = {} + end if not serverQueue[Identifier][player] then serverQueue[Identifier][player] = {} end diff --git a/src/Index/Signal/init.luau b/src/Index/Signal/init.luau index 567ab01..f7fe2a3 100644 --- a/src/Index/Signal/init.luau +++ b/src/Index/Signal/init.luau @@ -53,6 +53,12 @@ function Signal:Wait(): number return coroutine.yield() end +function Signal:DeferFire(...: any): () + for _, handle in self do + task.defer(handle.fn, ...) + end +end + function Signal:Fire(...: any): () for _, handle in self do task.spawn(handle.fn, ...) diff --git a/src/init.luau b/src/init.luau index 7b183f1..ccc8644 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,5 +1,5 @@ -- Warp Library (@Eternity_Devs) --- version 1.0.10 +-- version 1.0.11 --!strict --!native --!optimize 2 diff --git a/wally.toml b/wally.toml index 193ac0c..71d26fb 100644 --- a/wally.toml +++ b/wally.toml @@ -1,6 +1,6 @@ [package] name = "imezx/warp" -version = "1.0.10" +version = "1.0.11" registry = "https://github.com/UpliftGames/wally-index" realm = "shared" license = "MIT"