2024-01-30 06:36:08 +00:00
|
|
|
--!native
|
2024-01-05 12:14:38 +00:00
|
|
|
--!strict
|
2024-03-13 01:13:01 +00:00
|
|
|
--!optimize 2
|
2024-01-05 12:14:38 +00:00
|
|
|
local ServerProcess = {}
|
|
|
|
|
|
|
|
local RunService = game:GetService("RunService")
|
|
|
|
local Players = game:GetService("Players")
|
|
|
|
local Util = script.Parent.Parent.Util
|
|
|
|
|
|
|
|
local Type = require(script.Parent.Parent.Type)
|
|
|
|
local Event = require(script.Parent.Parent.Event)
|
|
|
|
local Spawn = require(Util.Spawn)
|
|
|
|
local Key = require(Util.Key)
|
|
|
|
local RateLimit = require(Util.RateLimit)
|
2024-03-13 01:13:01 +00:00
|
|
|
local Buffer = require(Util.Buffer)
|
2024-04-02 06:10:21 +00:00
|
|
|
local Logger = require(script.Logger)
|
2024-01-05 12:14:38 +00:00
|
|
|
|
|
|
|
local serverQueue: Type.QueueMap = {}
|
|
|
|
local unreliableServerQueue: Type.QueueMap = {}
|
|
|
|
local serverCallback: Type.CallbackMap = {}
|
|
|
|
local serverRequestQueue: Type.QueueMap = {}
|
2024-01-31 06:33:19 +00:00
|
|
|
|
2024-01-05 12:14:38 +00:00
|
|
|
local queueOut: {
|
|
|
|
[Player]: {
|
|
|
|
[string]: {any},
|
|
|
|
}
|
|
|
|
} = {}
|
|
|
|
local queueIn: {
|
|
|
|
[string]: {
|
|
|
|
[Player]: {any},
|
|
|
|
}
|
|
|
|
} = {}
|
|
|
|
local queueInRequest: {
|
|
|
|
[number]: {
|
|
|
|
[string]: {
|
|
|
|
[Player]: {any}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} = {}
|
|
|
|
local queueOutRequest: {
|
|
|
|
[number]: {
|
|
|
|
[string]: {
|
|
|
|
[Player]: {any}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} = {}
|
2024-04-02 06:10:21 +00:00
|
|
|
local logger: {
|
|
|
|
[string]: boolean
|
|
|
|
} = {}
|
2024-04-13 02:00:52 +00:00
|
|
|
local players: {
|
|
|
|
Player
|
|
|
|
} = {}
|
2024-04-02 06:10:21 +00:00
|
|
|
|
2024-01-05 12:14:38 +00:00
|
|
|
queueInRequest[1] = {}
|
|
|
|
queueInRequest[2] = {}
|
|
|
|
queueOutRequest[1] = {}
|
|
|
|
queueOutRequest[2] = {}
|
|
|
|
|
|
|
|
local ReliableEvent = Event.Reliable
|
|
|
|
local UnreliableEvent = Event.Unreliable
|
|
|
|
local RequestEvent = Event.Request
|
|
|
|
|
|
|
|
local function initializeEachPlayer(player: Player)
|
2024-04-13 02:00:52 +00:00
|
|
|
players = Players:GetPlayers()
|
2024-01-05 12:14:38 +00:00
|
|
|
if not player then return end
|
|
|
|
if not queueOut[player] then
|
|
|
|
queueOut[player] = {}
|
|
|
|
end
|
2024-03-02 16:43:36 +00:00
|
|
|
for Identifier: string in serverQueue do
|
|
|
|
if not player then break end
|
2024-01-05 12:14:38 +00:00
|
|
|
if not queueOut[player][Identifier] then
|
|
|
|
queueOut[player][Identifier] = {}
|
|
|
|
end
|
|
|
|
if not serverRequestQueue[Identifier][player] then
|
|
|
|
serverRequestQueue[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
if not queueIn[Identifier][player] then
|
|
|
|
queueIn[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
if not queueInRequest[1][Identifier][player] then
|
|
|
|
queueInRequest[1][Identifier][player] = {}
|
|
|
|
queueInRequest[2][Identifier][player] = {}
|
|
|
|
end
|
|
|
|
if not queueOutRequest[1][Identifier][player] then
|
|
|
|
queueOutRequest[1][Identifier][player] = {}
|
|
|
|
queueOutRequest[2][Identifier][player] = {}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Players.PlayerAdded:Connect(initializeEachPlayer)
|
2024-04-13 02:00:52 +00:00
|
|
|
Players.PlayerRemoving:Connect(function()
|
|
|
|
players = Players:GetPlayers()
|
|
|
|
end)
|
2024-01-05 12:14:38 +00:00
|
|
|
|
|
|
|
function ServerProcess.insertQueue(Identifier: string, reliable: boolean, player: Player, ...: any)
|
|
|
|
if not reliable then
|
|
|
|
if not unreliableServerQueue[Identifier][player] then
|
|
|
|
unreliableServerQueue[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
table.insert(unreliableServerQueue[Identifier][player], { ... })
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if not serverQueue[Identifier][player] then
|
|
|
|
serverQueue[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
table.insert(serverQueue[Identifier][player], { ... })
|
|
|
|
end
|
|
|
|
|
|
|
|
function ServerProcess.insertRequest(Identifier: string, timeout: number, player: Player, ...: any)
|
|
|
|
if not serverQueue[Identifier][player] then
|
|
|
|
serverQueue[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
local yieldThread: thread, start = coroutine.running(), os.clock()
|
|
|
|
local cancel = task.delay(timeout, function()
|
|
|
|
task.spawn(yieldThread, nil)
|
|
|
|
end)
|
|
|
|
table.insert(serverRequestQueue[Identifier][player], { tostring(Key()), function(...: any)
|
|
|
|
if (os.clock() - start) > timeout then return end
|
|
|
|
task.cancel(cancel)
|
|
|
|
task.spawn(yieldThread, ...)
|
|
|
|
end :: any, { ... } :: any })
|
|
|
|
return coroutine.yield()
|
|
|
|
end
|
|
|
|
|
|
|
|
function ServerProcess.add(Identifier: string, originId: string, ratelimit: Type.rateLimitArg)
|
|
|
|
if not serverQueue[Identifier] then
|
2024-01-06 03:41:10 +00:00
|
|
|
RateLimit.create(originId, ratelimit.maxEntrance or 200, ratelimit.interval or 2)
|
2024-04-09 08:49:06 +00:00
|
|
|
if not serverQueue[Identifier] then
|
|
|
|
serverQueue[Identifier] = {}
|
|
|
|
end
|
|
|
|
if not unreliableServerQueue[Identifier] then
|
|
|
|
unreliableServerQueue[Identifier] = {}
|
|
|
|
end
|
|
|
|
if not serverCallback[Identifier] then
|
|
|
|
serverCallback[Identifier] = {}
|
|
|
|
end
|
|
|
|
if not serverRequestQueue[Identifier] then
|
|
|
|
serverRequestQueue[Identifier] = {}
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
|
2024-04-09 08:49:06 +00:00
|
|
|
if not queueIn[Identifier] then
|
|
|
|
queueIn[Identifier] = {}
|
|
|
|
end
|
|
|
|
if not queueInRequest[1][Identifier] then
|
|
|
|
queueInRequest[1][Identifier] = {}
|
|
|
|
end
|
|
|
|
if not queueInRequest[2][Identifier] then
|
|
|
|
queueInRequest[2][Identifier] = {}
|
|
|
|
end
|
|
|
|
if not queueOutRequest[1][Identifier] then
|
|
|
|
queueOutRequest[1][Identifier] = {}
|
|
|
|
end
|
|
|
|
if not queueOutRequest[2][Identifier] then
|
|
|
|
queueOutRequest[2][Identifier] = {}
|
|
|
|
end
|
2024-01-06 03:41:10 +00:00
|
|
|
|
|
|
|
for _, player: Player in ipairs(Players:GetPlayers()) do
|
|
|
|
task.spawn(initializeEachPlayer, player)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-04-02 06:10:21 +00:00
|
|
|
function ServerProcess.logger(Identifier: string, store: boolean, log: boolean)
|
|
|
|
logger[Identifier] = store
|
|
|
|
Logger.write(Identifier, `state: change -> {log == true and "enabled" or "disabled"} logger.`, log)
|
|
|
|
end
|
|
|
|
|
|
|
|
function ServerProcess.getlogs(Identifier: string)
|
|
|
|
return Logger.read(Identifier)
|
|
|
|
end
|
|
|
|
|
2024-01-05 12:14:38 +00:00
|
|
|
function ServerProcess.addCallback(Identifier: string, key: string, callback)
|
|
|
|
serverCallback[Identifier][key] = callback
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: change -> new callback added.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function ServerProcess.removeCallback(Identifier: string, key: string)
|
|
|
|
serverCallback[Identifier][key] = nil
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: change -> removed a callback.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function ServerProcess.start()
|
2024-04-12 12:15:22 +00:00
|
|
|
debug.setmemorycategory("Warp")
|
2024-01-05 12:14:38 +00:00
|
|
|
RunService.PostSimulation:Connect(function()
|
|
|
|
for Identifier: string, players in unreliableServerQueue do
|
|
|
|
for player: Player, data: any in players do
|
|
|
|
if #data == 0 then continue end
|
2024-03-13 01:13:01 +00:00
|
|
|
UnreliableEvent:FireClient(player, Buffer.revert(Identifier), data)
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#data} data.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
table.clear(data)
|
|
|
|
end
|
|
|
|
end
|
2024-04-13 02:00:52 +00:00
|
|
|
for _, player: Player in ipairs(players) do
|
|
|
|
if not player or not queueOut[player] then continue end
|
2024-01-05 12:14:38 +00:00
|
|
|
for Identifier: string, data: any in queueOut[player] do
|
|
|
|
if #data == 0 then continue end
|
2024-03-13 01:13:01 +00:00
|
|
|
ReliableEvent:FireClient(player, Buffer.revert(Identifier), data)
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: out -> reliable -> {#data} data.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
table.clear(data)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for Identifier: string, players in serverQueue do
|
2024-04-02 06:10:21 +00:00
|
|
|
local callback = serverCallback[Identifier] or nil
|
2024-01-05 12:14:38 +00:00
|
|
|
for player: Player, data in players do
|
2024-01-30 13:14:29 +00:00
|
|
|
if #data > 0 and queueOut[player] then
|
2024-01-05 12:14:38 +00:00
|
|
|
queueOut[player][Identifier] = table.clone(data)
|
|
|
|
table.clear(data)
|
|
|
|
end
|
|
|
|
if #serverRequestQueue[Identifier][player] > 0 then
|
|
|
|
for _, requestData in serverRequestQueue[Identifier][player] do
|
|
|
|
if not requestData[3] then continue end
|
|
|
|
table.insert(queueOutRequest[1][Identifier][player], { requestData[1], requestData[3] })
|
|
|
|
table.remove(requestData, #requestData)
|
|
|
|
end
|
|
|
|
end
|
2024-04-02 06:10:21 +00:00
|
|
|
if callback then
|
2024-01-05 12:14:38 +00:00
|
|
|
if #queueIn[Identifier][player] > 0 then
|
|
|
|
for _, packedDatas: any in queueIn[Identifier][player] do
|
|
|
|
if #packedDatas == 0 then continue end
|
2024-04-02 06:10:21 +00:00
|
|
|
for _, fn: any in callback do
|
2024-03-18 05:50:04 +00:00
|
|
|
for i=1,math.min(1e3, #packedDatas) do
|
|
|
|
Spawn(fn, player, table.unpack(packedDatas[i] or {}))
|
2024-01-05 12:14:38 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.clear(queueIn[Identifier][player])
|
|
|
|
end
|
|
|
|
if #queueInRequest[1][Identifier][player] > 0 then
|
|
|
|
for idx, packetDatas: any in queueInRequest[1][Identifier][player] do
|
|
|
|
if #packetDatas == 0 then continue end
|
2024-04-02 06:10:21 +00:00
|
|
|
for _, fn: any in callback do
|
2024-03-18 05:50:04 +00:00
|
|
|
for i=1,math.min(1e3, #packetDatas) do
|
|
|
|
local packetData = packetDatas[i]
|
|
|
|
if not packetData then continue end
|
2024-01-05 12:14:38 +00:00
|
|
|
Spawn(function()
|
|
|
|
local requestReturn = { fn(player, table.unpack(packetData[2])) }
|
|
|
|
table.insert(queueOutRequest[2][Identifier][player], { packetData[1], requestReturn })
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.clear(queueInRequest[1][Identifier][player])
|
|
|
|
end
|
|
|
|
if #queueInRequest[2][Identifier][player] > 0 then
|
|
|
|
for _, packetDatas: any in queueInRequest[2][Identifier][player] do
|
2024-03-18 05:50:04 +00:00
|
|
|
for idx, packetData in packetDatas do
|
2024-01-05 12:14:38 +00:00
|
|
|
if #packetData == 1 then continue end
|
2024-03-18 05:50:04 +00:00
|
|
|
for y=1, math.min(1e3, #serverRequestQueue[Identifier][player]) do
|
|
|
|
local serverRequest = serverRequestQueue[Identifier][player][y]
|
|
|
|
if not serverRequest then continue end
|
2024-01-05 12:14:38 +00:00
|
|
|
if serverRequest[1] == packetData[1] then
|
|
|
|
Spawn(serverRequest[2], table.unpack(packetData[2]))
|
2024-03-18 05:50:04 +00:00
|
|
|
table.remove(packetDatas, idx)
|
|
|
|
table.remove(serverRequestQueue[Identifier][player], y)
|
2024-01-05 12:14:38 +00:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.clear(queueInRequest[2][Identifier][player])
|
|
|
|
end
|
|
|
|
for player: Player, requestsData: any in queueOutRequest[1][Identifier] do
|
|
|
|
if #requestsData == 0 then continue end
|
2024-03-13 01:13:01 +00:00
|
|
|
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\1", requestsData)
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: out -> request -> {#requestsData} data.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
table.clear(requestsData)
|
|
|
|
end
|
|
|
|
for player: Player, toReturnDatas: any in queueOutRequest[2][Identifier] do
|
|
|
|
if #toReturnDatas == 0 then continue end
|
2024-03-13 01:13:01 +00:00
|
|
|
RequestEvent:FireClient(player, Buffer.revert(Identifier), "\0", toReturnDatas)
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: out -> return request -> {#toReturnDatas} data.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
table.clear(toReturnDatas)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
2024-03-13 01:13:01 +00:00
|
|
|
local function onServerNetworkReceive(player: Player, Identifier: any, data: any)
|
2024-01-05 12:14:38 +00:00
|
|
|
if not Identifier or not data then return end
|
2024-03-13 01:13:01 +00:00
|
|
|
Identifier = Buffer.convert(Identifier)
|
2024-01-05 12:14:38 +00:00
|
|
|
if not serverQueue[Identifier] then
|
|
|
|
serverQueue[Identifier] = {}
|
|
|
|
end
|
|
|
|
if not serverQueue[Identifier][player] then
|
|
|
|
serverQueue[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
if not queueIn[Identifier][player] then
|
|
|
|
queueIn[Identifier][player] = {}
|
|
|
|
end
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: in -> net -> {#data} data.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
table.insert(queueIn[Identifier][player], data)
|
|
|
|
end
|
|
|
|
ReliableEvent.OnServerEvent:Connect(onServerNetworkReceive)
|
|
|
|
UnreliableEvent.OnServerEvent:Connect(onServerNetworkReceive)
|
2024-03-13 01:13:01 +00:00
|
|
|
RequestEvent.OnServerEvent:Connect(function(player: Player, Identifier: any, action: string, data: any)
|
2024-01-05 12:14:38 +00:00
|
|
|
if not Identifier or not data then return end
|
2024-03-13 01:13:01 +00:00
|
|
|
Identifier = Buffer.convert(Identifier)
|
2024-01-05 12:14:38 +00:00
|
|
|
if not queueInRequest[1][Identifier][player] then
|
|
|
|
queueInRequest[1][Identifier][player] = {}
|
|
|
|
queueInRequest[2][Identifier][player] = {}
|
|
|
|
end
|
|
|
|
if not serverQueue[Identifier][player] then
|
|
|
|
serverQueue[Identifier][player] = {}
|
|
|
|
end
|
|
|
|
if action == "\1" then
|
|
|
|
table.insert(queueInRequest[1][Identifier][player], data)
|
|
|
|
else
|
|
|
|
table.insert(queueInRequest[2][Identifier][player], data)
|
|
|
|
end
|
2024-04-02 06:10:21 +00:00
|
|
|
if logger[Identifier] then
|
|
|
|
task.defer(Logger.write, Identifier, `state: in -> request -> {#data} data.`)
|
|
|
|
end
|
2024-01-05 12:14:38 +00:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, player: Player in ipairs(Players:GetPlayers()) do
|
|
|
|
task.spawn(initializeEachPlayer, player)
|
|
|
|
end
|
|
|
|
|
2024-01-31 06:33:19 +00:00
|
|
|
return ServerProcess
|