From 94b0c5a919a1ff4b93dd79d729e56befbb4ab7c4 Mon Sep 17 00:00:00 2001 From: khtsly Date: Thu, 9 Apr 2026 00:35:48 +0700 Subject: [PATCH] feat: hash-map for listeners --- src/Client/init.luau | 63 ++++++++++++++++++------------------ src/Replication/init.luau | 4 ++- src/Server/init.luau | 67 ++++++++++++++++++++------------------- src/init.luau | 3 -- 4 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/Client/init.luau b/src/Client/init.luau index 01e9c8d..4d5f74c 100644 --- a/src/Client/init.luau +++ b/src/Client/init.luau @@ -23,7 +23,7 @@ type Event = { local queueEvent: { { any } } = {} local queueUnreliableEvent: { { any } } = {} -local eventListeners: { Event } = {} +local eventListeners: { [number]: { Event } } = {} local eventSchemas: { [number]: Buffer.SchemaType } = {} local pendingInvokes: { [string]: thread } = {} @@ -52,13 +52,21 @@ Client.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): local id = Replication.get_id[remoteName] if not id then warn(`[Warp]: ".Connect"::"{remoteName}" does not exist, likely its not registered on the server yet.`) - return { Connected = false, Disconnect = function() return end } :: Connection + return { + Connected = false, + Disconnect = function() + return + end, + } :: Connection end local detail = { i = id, c = fn, } - table.insert(eventListeners, detail) + if not eventListeners[id] then + eventListeners[id] = {} + end + table.insert(eventListeners[id], detail) return { Connected = true, Disconnect = function(self: Connection) @@ -66,9 +74,12 @@ Client.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): return end self.Connected = false - local idx = table.find(eventListeners, detail) - if idx then - table.remove(eventListeners, idx) + local bucket = eventListeners[detail.i] + if bucket then + local idx = table.find(bucket, detail) + if idx then + table.remove(bucket, idx) + end end end, } :: Connection @@ -105,11 +116,7 @@ Client.DisconnectAll = function(remoteName: string) if not id then return end - for idx = #eventListeners, 1, -1 do - if eventListeners[idx].i == id then - table.remove(eventListeners, idx) - end - end + eventListeners[id] = nil end --@remoteName string @@ -177,35 +184,27 @@ if RunService:IsClient() then continue end if remote == 1 then - if #eventListeners == 0 then - continue - end local remoteName = content[1] local id = content[2] local args = content[3] - for _, connection in eventListeners do - if connection.i == remoteName then - Thread(function() - local results = { connection.c(table.unpack(args)) } - table.insert(queueEvent, { - 1, - { id, results } :: any, - }) - end) - break - end + local connections = eventListeners[remoteName] + if connections and #connections > 0 then + Thread(function() + local results = { connections[1].c(table.unpack(args)) } + table.insert(queueEvent, { + 1, + { id, results } :: any, + }) + end) end continue end end - if #eventListeners == 0 then - continue - end - for _, connection in eventListeners do - if connection.i ~= remote then - continue + local connections = eventListeners[remote] + if connections then + for _, connection in connections do + Thread(connection.c, table.unpack(content)) end - Thread(connection.c, table.unpack(content)) end end end diff --git a/src/Replication/init.luau b/src/Replication/init.luau index 224c501..1b3fb68 100644 --- a/src/Replication/init.luau +++ b/src/Replication/init.luau @@ -124,7 +124,9 @@ else end) Replication.remove = function(player: Player) - table.remove(replication_ready, table.find(replication_ready, player)) + local idx = table.find(replication_ready, player) + if not idx then return end + table.remove(replication_ready, idx) end end diff --git a/src/Server/init.luau b/src/Server/init.luau index 80d1565..c7727f5 100644 --- a/src/Server/init.luau +++ b/src/Server/init.luau @@ -30,7 +30,7 @@ local queueEvent: { local queueUnreliableEvent: { [Player]: { { any } }, } = {} -local eventListeners: { Event } = {} +local eventListeners: { [number]: { Event } } = {} local eventSchemas: { [number]: Buffer.SchemaType } = {} local players_ready: { Player }, player_bytes: { [Player]: number } = {}, {} @@ -61,7 +61,10 @@ Server.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): i = Identifier.get_id(remoteName), c = fn, } - table.insert(eventListeners, detail) + if not eventListeners[detail.i] then + eventListeners[detail.i] = {} + end + table.insert(eventListeners[detail.i], detail) return { Connected = true, Disconnect = function(self: Connection) @@ -69,9 +72,12 @@ Server.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): return end self.Connected = false - local idx = table.find(eventListeners, detail) - if idx then - table.remove(eventListeners, idx) + local bucket = eventListeners[detail.i] + if bucket then + local idx = table.find(bucket, detail) + if idx then + table.remove(bucket, idx) + end end end, } :: Connection @@ -108,11 +114,7 @@ Server.DisconnectAll = function(remoteName: string) if not id then return end - for idx = #eventListeners, 1, -1 do - if eventListeners[idx].i == id then - table.remove(eventListeners, idx) - end - end + eventListeners[id] = nil end --@remoteName string @@ -149,7 +151,9 @@ end -- Fire an event to all players except specified ones. Server.FireExcept = function(remoteName: string, reliable: boolean, except: { Player }, ...: any?) for _, player: Player in players_ready do - if table.find(except, player) then continue end + if table.find(except, player) then + continue + end Server.Fire(remoteName, reliable, player, ...) end end @@ -188,7 +192,9 @@ if RunService:IsServer() then end if not RunService:IsStudio() then local bytes: number = (player_bytes[player] or 0) + math.max(buffer.len(b), 800) - if bytes > 8e3 then return end + if bytes > 8e3 then + return + end player_bytes[player] = bytes end @@ -214,32 +220,27 @@ if RunService:IsServer() then local remoteName = content[1] local id = content[2] local args = content[3] - for _, connection in eventListeners do - if connection.i == remoteName then - Thread(function() - local results = { connection.c(player, table.unpack(args)) } - if not queueEvent[player] then - queueEvent[player] = {} :: any - end - table.insert(queueEvent[player], { - 0, - { id, results } :: any, - }) - end) - break - end + local connections = eventListeners[remoteName] + if connections and #connections > 0 then + Thread(function() + local results = { connections[1].c(player, table.unpack(args)) } + if not queueEvent[player] then + queueEvent[player] = {} :: any + end + table.insert(queueEvent[player], { + 0, + { id, results } :: any, + }) + end) end continue end end - if #eventListeners == 0 then - continue - end - for _, connection in eventListeners do - if connection.i ~= remote then - continue + local connections = eventListeners[remote] + if connections then + for _, connection in connections do + Thread(connection.c, player, table.unpack(content)) end - Thread(connection.c, player, table.unpack(content)) end end end diff --git a/src/init.luau b/src/init.luau index eae5670..b5d0989 100644 --- a/src/init.luau +++ b/src/init.luau @@ -12,9 +12,6 @@ if game.RunService:IsServer() then if not script:FindFirstChild("UnreliableEvent") then Instance.new("UnreliableRemoteEvent", script).Name = "UnreliableEvent" end - if not script:FindFirstChild("Function") then - Instance.new("RemoteFunction", script).Name = "Function" - end end local Client = require("@self/Client")