diff --git a/modules/comm/Client/ClientRemoteSignal.lua b/modules/comm/Client/ClientRemoteSignal.lua index 285bbc00..d3745a83 100644 --- a/modules/comm/Client/ClientRemoteSignal.lua +++ b/modules/comm/Client/ClientRemoteSignal.lua @@ -17,10 +17,12 @@ ClientRemoteSignal.__index = ClientRemoteSignal @within ClientRemoteSignal @interface Connection .Disconnect () -> () + + Represents a connection. ]=] function ClientRemoteSignal.new( - re: RemoteEvent, + re: RemoteEvent | UnreliableRemoteEvent, inboundMiddleware: Types.ClientMiddleware?, outboudMiddleware: Types.ClientMiddleware? ) @@ -37,7 +39,7 @@ function ClientRemoteSignal.new( self._signal = Signal.new() self._reConn = self._re.OnClientEvent:Connect(function(...) local args = table.pack(...) - for _, middlewareFunc in ipairs(inboundMiddleware) do + for _, middlewareFunc in inboundMiddleware do local middlewareResult = table.pack(middlewareFunc(args)) if not middlewareResult[1] then return @@ -54,7 +56,7 @@ end function ClientRemoteSignal:_processOutboundMiddleware(...: any) local args = table.pack(...) - for _, middlewareFunc in ipairs(self._outbound) do + for _, middlewareFunc in self._outbound do local middlewareResult = table.pack(middlewareFunc(args)) if not middlewareResult[1] then return table.unpack(middlewareResult, 2, middlewareResult.n) diff --git a/modules/comm/Server/RemoteSignal.lua b/modules/comm/Server/RemoteSignal.lua index 20c93c78..c9b32b6c 100644 --- a/modules/comm/Server/RemoteSignal.lua +++ b/modules/comm/Server/RemoteSignal.lua @@ -20,16 +20,19 @@ RemoteSignal.__index = RemoteSignal @interface Connection .Disconnect () -> nil .Connected boolean + + Represents a connection. ]=] function RemoteSignal.new( parent: Instance, name: string, + unreliable: boolean?, inboundMiddleware: Types.ServerMiddleware?, outboundMiddleware: Types.ServerMiddleware? ) local self = setmetatable({}, RemoteSignal) - self._re = Instance.new("RemoteEvent") + self._re = if unreliable == true then Instance.new("UnreliableRemoteEvent") else Instance.new("RemoteEvent") self._re.Name = name self._re.Parent = parent if outboundMiddleware and #outboundMiddleware > 0 then @@ -43,7 +46,7 @@ function RemoteSignal.new( self._signal = Signal.new() self._re.OnServerEvent:Connect(function(player, ...) local args = table.pack(...) - for _, middlewareFunc in ipairs(inboundMiddleware) do + for _, middlewareFunc in inboundMiddleware do local middlewareResult = table.pack(middlewareFunc(player, args)) if not middlewareResult[1] then return @@ -58,6 +61,15 @@ function RemoteSignal.new( return self end +--[=[ + @return boolean + Returns `true` if the underlying RemoteSignal is bound to an + UnreliableRemoteEvent object. +]=] +function RemoteSignal:IsUnreliable(): boolean + return self._re:IsA("UnreliableRemoteEvent") +end + --[=[ @param fn (player: Player, ...: any) -> nil -- The function to connect @return Connection @@ -78,7 +90,7 @@ function RemoteSignal:_processOutboundMiddleware(player: Player?, ...: any) return ... end local args = table.pack(...) - for _, middlewareFunc in ipairs(self._outbound) do + for _, middlewareFunc in self._outbound do local middlewareResult = table.pack(middlewareFunc(player, args)) if not middlewareResult[1] then return table.unpack(middlewareResult, 2, middlewareResult.n) @@ -157,7 +169,7 @@ end ``` ]=] function RemoteSignal:FireFilter(predicate: (Player, ...any) -> boolean, ...: any) - for _, player in ipairs(Players:GetPlayers()) do + for _, player in Players:GetPlayers() do if predicate(player, ...) then self._re:FireClient(player, self:_processOutboundMiddleware(nil, ...)) end @@ -181,7 +193,7 @@ end ``` ]=] function RemoteSignal:FireFor(players: { Player }, ...: any) - for _, player in ipairs(players) do + for _, player in players do self._re:FireClient(player, self:_processOutboundMiddleware(nil, ...)) end end diff --git a/modules/comm/Server/ServerComm.lua b/modules/comm/Server/ServerComm.lua index 581059f2..3f7b3233 100644 --- a/modules/comm/Server/ServerComm.lua +++ b/modules/comm/Server/ServerComm.lua @@ -3,8 +3,8 @@ -- December 20, 2021 local Comm = require(script.Parent) -local Util = require(script.Parent.Parent.Util) local Types = require(script.Parent.Parent.Types) +local Util = require(script.Parent.Parent.Util) --[=[ @class ServerComm @@ -116,6 +116,7 @@ end --[=[ @param name string + @param unreliable boolean? @param inboundMiddleware ServerMiddleware? @param outboundMiddleware ServerMiddleware? @return RemoteSignal @@ -123,6 +124,10 @@ end Creates a signal that can be used to fire data to the clients or receive data from the clients. + By default, signals use RemoteEvents internally. However, if + the `unreliable` argument is set to `true`, then an + UnreliableRemoteEvent will be used instead. + ```lua local mySignal = serverComm:CreateSignal("MySignal") @@ -140,10 +145,11 @@ end ]=] function ServerComm:CreateSignal( name: string, + unreliable: boolean?, inboundMiddleware: Types.ServerMiddleware?, outboundMiddleware: Types.ServerMiddleware? ) - return Comm.CreateSignal(self._instancesFolder, name, inboundMiddleware, outboundMiddleware) + return Comm.CreateSignal(self._instancesFolder, name, unreliable, inboundMiddleware, outboundMiddleware) end --[=[ diff --git a/modules/comm/Server/init.lua b/modules/comm/Server/init.lua index efd09099..7828266d 100644 --- a/modules/comm/Server/init.lua +++ b/modules/comm/Server/init.lua @@ -1,7 +1,7 @@ -local Util = require(script.Parent.Util) -local RemoteSignal = require(script.RemoteSignal) local RemoteProperty = require(script.RemoteProperty) +local RemoteSignal = require(script.RemoteSignal) local Types = require(script.Parent.Types) +local Util = require(script.Parent.Util) local Server = {} @@ -114,12 +114,13 @@ end function Server.CreateSignal( parent: Instance, name: string, + reliable: boolean?, inboundMiddleware: Types.ServerMiddleware?, outboundMiddleware: Types.ServerMiddleware? ) assert(Util.IsServer, "CreateSignal must be called from the server") local folder = Util.GetCommSubFolder(parent, "RE"):Expect("Failed to get Comm RE folder") - local rs = RemoteSignal.new(folder, name, inboundMiddleware, outboundMiddleware) + local rs = RemoteSignal.new(folder, name, reliable, inboundMiddleware, outboundMiddleware) return rs end diff --git a/modules/comm/wally.toml b/modules/comm/wally.toml index f7f96499..e6ffbb0e 100644 --- a/modules/comm/wally.toml +++ b/modules/comm/wally.toml @@ -1,13 +1,13 @@ [package] name = "sleitnick/comm" description = "Comm library for remote communication" -version = "0.3.2" +version = "1.0.0" license = "MIT" authors = ["Stephen Leitnick"] registry = "https://github.com/UpliftGames/wally-index" realm = "shared" [dependencies] -Signal = "sleitnick/signal@1" +Signal = "sleitnick/signal@2" Option = "sleitnick/option@1" Promise = "evaera/promise@4" diff --git a/modules/net/init.lua b/modules/net/init.lua index 659cbf84..13ab5f42 100644 --- a/modules/net/init.lua +++ b/modules/net/init.lua @@ -41,6 +41,40 @@ function Net:RemoteEvent(name: string): RemoteEvent end end +--[=[ + Gets an UnreliableRemoteEvent with the given name. + + On the server, if the UnreliableRemoteEvent does not + exist, then it will be created with the given name. + + On the client, if the UnreliableRemoteEvent does not + exist, then it will wait until it exists for at least + 10 seconds. If the UnreliableRemoteEvent does not exist + after 10 seconds, an error will be thrown. + + ```lua + local unreliableRemoteEvent = Net:UnreliableRemoteEvent("PositionChanged") + ``` +]=] +function Net:UnreliableRemoteEvent(name: string): UnreliableRemoteEvent + name = "URE/" .. name + if RunService:IsServer() then + local r = script:FindFirstChild(name) + if not r then + r = Instance.new("UnreliableRemoteEvent") + r.Name = name + r.Parent = script + end + return r + else + local r = script:WaitForChild(name, 10) + if not r then + error("Failed to find UnreliableRemoteEvent: " .. name, 2) + end + return r + end +end + --[=[ Connects a handler function to the given RemoteEvent. @@ -62,6 +96,27 @@ function Net:Connect(name: string, handler: (...any) -> ()): RBXScriptConnection end end +--[=[ + Connects a handler function to the given UnreliableRemoteEvent. + + ```lua + -- Client + Net:ConnectUnreliable("PositionChanged", function(position) + print("Position", position) + end) + + -- Server + Net:ConnectUnreliable("SomeEvent", function(player, ...) end) + ``` +]=] +function Net:ConnectUnreliable(name: string, handler: (...any) -> ()): RBXScriptConnection + if RunService:IsServer() then + return self:UnreliableRemoteEvent(name).OnServerEvent:Connect(handler) + else + return self:UnreliableRemoteEvent(name).OnClientEvent:Connect(handler) + end +end + --[=[ Gets a RemoteFunction with the given name. diff --git a/modules/net/wally.toml b/modules/net/wally.toml index ffffbb5d..2e637d07 100644 --- a/modules/net/wally.toml +++ b/modules/net/wally.toml @@ -1,7 +1,7 @@ [package] name = "sleitnick/net" description = "Static networking module" -version = "0.1.0" +version = "0.2.0" license = "MIT" authors = ["Stephen Leitnick"] registry = "https://github.com/UpliftGames/wally-index"