diff --git a/CHANGELOG.md b/CHANGELOG.md index 01deecf..d235e7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,22 @@ This project uses [semantic versioning](https://semver.org/spec/v2.0.0.html). -## [version](https://github.com/ffrostflame/BridgeNet2/releases/tag/v0.5.6): 9/25/2023 +## [version 1.0.0](https://github.com/ffrostflame/BridgeNet2/releases/tag/v0.5.6): 10/20/2023 + +### Added + +- Added an easy way to type payloads using generics. This will be elaborated on in documentation later + +### Fixes + +- Fixed sending singular nil values with nothing else in the frame +- Fixed a bug w/ the loading queue. Finally got around to that (https://github.com/ffrostflame/BridgeNet2/issues/35) +- Type improvements + +### Improvements + +- Added unique IDs to the invoke functionality. Should fix a multitude of bugs. +- Re-did rate limiting. I'm confident that it's stable. ## [version 0.5.6](https://github.com/ffrostflame/BridgeNet2/releases/tag/v0.5.6): 9/25/2023 diff --git a/LICENSE b/LICENSE index 7c5c0aa..735f6b0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2022 ffrostfall +Copyright 2023 ffrostfall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 689f25a..be6d130 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ -# BridgeNet2 v0.5.5 +# BridgeNet2 v1.0.0 ## Blazing fast & opinionated networking library designed to reduce bandwidth. @@ -15,4 +15,3 @@ Developers cannot fire a bridge with multiple parameters. This means you have to This library favors performance, and therefore we made choices that resulted in an opinionated library. BridgeNet2 never manipulates your data under the hood, but it does encourage developing in favor of performance. [Further Documentation](https://ffrostflame.github.io/BridgeNet2/) - diff --git a/sourcemap.json b/sourcemap.json index adce4d3..a068cb9 100644 --- a/sourcemap.json +++ b/sourcemap.json @@ -1 +1 @@ -{"name":"bridgenet2-test","className":"DataModel","filePaths":["testing.project.json"],"children":[{"name":"ReplicatedStorage","className":"ReplicatedStorage","children":[{"name":"Packages","className":"Folder","children":[{"name":"RemotePacketSizeCounter","className":"ModuleScript","filePaths":["Packages\\RemotePacketSizeCounter.lua"]},{"name":"TableKit","className":"ModuleScript","filePaths":["Packages\\TableKit.lua"]},{"name":"_Index","className":"Folder","children":[{"name":"ffrostflame_tablekit@0.2.4","className":"Folder","children":[{"name":"tablekit","className":"ModuleScript","filePaths":["Packages\\_Index\\ffrostflame_tablekit@0.2.4\\tablekit\\src\\init.luau","Packages\\_Index\\ffrostflame_tablekit@0.2.4\\tablekit\\default.project.json"]}]},{"name":"ffrostflame_wally-instance-manager@0.1.0","className":"Folder","children":[{"name":"wally-instance-manager","className":"ModuleScript","filePaths":["Packages\\_Index\\ffrostflame_wally-instance-manager@0.1.0\\wally-instance-manager\\src\\init.luau","Packages\\_Index\\ffrostflame_wally-instance-manager@0.1.0\\wally-instance-manager\\default.project.json"]}]},{"name":"pysephwasntavailable_remotepacketsizecounter@2.1.0","className":"Folder","children":[{"name":"remotepacketsizecounter","className":"ModuleScript","filePaths":["Packages\\_Index\\pysephwasntavailable_remotepacketsizecounter@2.1.0\\remotepacketsizecounter\\src\\init.luau","Packages\\_Index\\pysephwasntavailable_remotepacketsizecounter@2.1.0\\remotepacketsizecounter\\default.project.json"]}]}]},{"name":"wallyInstanceManager","className":"ModuleScript","filePaths":["Packages\\wallyInstanceManager.lua"]},{"name":"bridgenet2","className":"ModuleScript","filePaths":["src\\init.luau"],"children":[{"name":"Client","className":"ModuleScript","filePaths":["src\\Client\\init.luau"],"children":[{"name":"ClientBridge","className":"ModuleScript","filePaths":["src\\Client\\ClientBridge.luau"]},{"name":"ClientConnection","className":"ModuleScript","filePaths":["src\\Client\\ClientConnection.luau"]},{"name":"ClientIdentifiers","className":"ModuleScript","filePaths":["src\\Client\\ClientIdentifiers.luau"]},{"name":"ClientProcess","className":"ModuleScript","filePaths":["src\\Client\\ClientProcess.luau"]}]},{"name":"Constants","className":"ModuleScript","filePaths":["src\\Constants.luau"]},{"name":"PublicTypes","className":"ModuleScript","filePaths":["src\\PublicTypes.luau"]},{"name":"Server","className":"ModuleScript","filePaths":["src\\Server\\init.luau"],"children":[{"name":"HandleInvalidPlayer","className":"ModuleScript","filePaths":["src\\Server\\HandleInvalidPlayer.luau"]},{"name":"PlayerContainers","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\init.luau"],"children":[{"name":"All","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\All.luau"]},{"name":"Except","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\Except.luau"]},{"name":"Players","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\Players.luau"]},{"name":"Single","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\Single.luau"]}]},{"name":"ServerBridge","className":"ModuleScript","filePaths":["src\\Server\\ServerBridge.luau"]},{"name":"ServerConnection","className":"ModuleScript","filePaths":["src\\Server\\ServerConnection.luau"]},{"name":"ServerIdentifiers","className":"ModuleScript","filePaths":["src\\Server\\ServerIdentifiers.luau"]},{"name":"ServerProcess","className":"ModuleScript","filePaths":["src\\Server\\ServerProcess.luau"]}]},{"name":"Studio","className":"Folder","children":[{"name":"MockBridge","className":"ModuleScript","filePaths":["src\\Studio\\MockBridge.luau"]},{"name":"MockConnection","className":"ModuleScript","filePaths":["src\\Studio\\MockConnection.luau"]},{"name":"MockIdentifiers","className":"ModuleScript","filePaths":["src\\Studio\\MockIdentifiers.luau"]}]},{"name":"Types","className":"ModuleScript","filePaths":["src\\Types.luau"]},{"name":"Utilities","className":"Folder","children":[{"name":"NetworkUtils","className":"ModuleScript","filePaths":["src\\Utilities\\NetworkUtils.luau"]},{"name":"Output","className":"ModuleScript","filePaths":["src\\Utilities\\Output.luau"]},{"name":"RecycledSpawn","className":"ModuleScript","filePaths":["src\\Utilities\\RecycledSpawn.luau"]},{"name":"isEditMode","className":"ModuleScript","filePaths":["src\\Utilities\\isEditMode.luau"]},{"name":"tostringData","className":"ModuleScript","filePaths":["src\\Utilities\\tostringData.luau"]}]},{"name":"version","className":"ModuleScript","filePaths":["src\\version.luau"]}]}]},{"name":"benches","className":"Folder","children":[{"name":"Hex.bench","className":"ModuleScript","filePaths":["benchmarks\\Hex.bench.luau"]}]},{"name":"framework","className":"ModuleScript","filePaths":["testing/framework\\init.luau"],"children":[{"name":"bootstrapper","className":"ModuleScript","filePaths":["testing/framework\\bootstrapper.luau"]},{"name":"expect","className":"ModuleScript","filePaths":["testing/framework\\expect.luau"]}]}]},{"name":"ServerScriptService","className":"ServerScriptService","children":[{"name":"featureTests","className":"Script","filePaths":["testing/tests/server\\featureTests\\init.server.luau"]}]},{"name":"StarterPlayer","className":"StarterPlayer","children":[{"name":"StarterPlayerScripts","className":"StarterPlayerScripts","children":[{"name":"featureTests","className":"LocalScript","filePaths":["testing/tests/client\\featureTests\\init.client.luau"]}]}]}]} \ No newline at end of file +{"name":"bridgenet2-test","className":"DataModel","filePaths":["testing.project.json"],"children":[{"name":"ReplicatedStorage","className":"ReplicatedStorage","children":[{"name":"Packages","className":"Folder","children":[{"name":"RemotePacketSizeCounter","className":"ModuleScript","filePaths":["Packages\\RemotePacketSizeCounter.lua"]},{"name":"TableKit","className":"ModuleScript","filePaths":["Packages\\TableKit.lua"]},{"name":"_Index","className":"Folder","children":[{"name":"ffrostflame_tablekit@0.2.4","className":"Folder","children":[{"name":"tablekit","className":"ModuleScript","filePaths":["Packages\\_Index\\ffrostflame_tablekit@0.2.4\\tablekit\\src\\init.luau","Packages\\_Index\\ffrostflame_tablekit@0.2.4\\tablekit\\default.project.json"]}]},{"name":"ffrostflame_wally-instance-manager@0.1.0","className":"Folder","children":[{"name":"wally-instance-manager","className":"ModuleScript","filePaths":["Packages\\_Index\\ffrostflame_wally-instance-manager@0.1.0\\wally-instance-manager\\src\\init.luau","Packages\\_Index\\ffrostflame_wally-instance-manager@0.1.0\\wally-instance-manager\\default.project.json"]}]},{"name":"pysephwasntavailable_remotepacketsizecounter@2.1.0","className":"Folder","children":[{"name":"remotepacketsizecounter","className":"ModuleScript","filePaths":["Packages\\_Index\\pysephwasntavailable_remotepacketsizecounter@2.1.0\\remotepacketsizecounter\\src\\init.luau","Packages\\_Index\\pysephwasntavailable_remotepacketsizecounter@2.1.0\\remotepacketsizecounter\\default.project.json"]}]}]},{"name":"wallyInstanceManager","className":"ModuleScript","filePaths":["Packages\\wallyInstanceManager.lua"]},{"name":"bridgenet2","className":"ModuleScript","filePaths":["src\\init.luau"],"children":[{"name":"Client","className":"ModuleScript","filePaths":["src\\Client\\init.luau"],"children":[{"name":"ClientBridge","className":"ModuleScript","filePaths":["src\\Client\\ClientBridge.luau"]},{"name":"ClientConnection","className":"ModuleScript","filePaths":["src\\Client\\ClientConnection.luau"]},{"name":"ClientIdentifiers","className":"ModuleScript","filePaths":["src\\Client\\ClientIdentifiers.luau"]},{"name":"ClientProcess","className":"ModuleScript","filePaths":["src\\Client\\ClientProcess.luau"]}]},{"name":"Constants","className":"ModuleScript","filePaths":["src\\Constants.luau"]},{"name":"ExportedTypes","className":"ModuleScript","filePaths":["src\\ExportedTypes.luau"]},{"name":"PublicTypes","className":"ModuleScript","filePaths":["src\\PublicTypes.luau"]},{"name":"Server","className":"ModuleScript","filePaths":["src\\Server\\init.luau"],"children":[{"name":"HandleInvalidPlayer","className":"ModuleScript","filePaths":["src\\Server\\HandleInvalidPlayer.luau"]},{"name":"PlayerContainers","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\init.luau"],"children":[{"name":"All","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\All.luau"]},{"name":"Except","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\Except.luau"]},{"name":"Players","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\Players.luau"]},{"name":"Single","className":"ModuleScript","filePaths":["src\\Server\\PlayerContainers\\Single.luau"]}]},{"name":"ServerBridge","className":"ModuleScript","filePaths":["src\\Server\\ServerBridge.luau"]},{"name":"ServerConnection","className":"ModuleScript","filePaths":["src\\Server\\ServerConnection.luau"]},{"name":"ServerIdentifiers","className":"ModuleScript","filePaths":["src\\Server\\ServerIdentifiers.luau"]},{"name":"ServerProcess","className":"ModuleScript","filePaths":["src\\Server\\ServerProcess.luau"]}]},{"name":"Studio","className":"Folder","children":[{"name":"MockBridge","className":"ModuleScript","filePaths":["src\\Studio\\MockBridge.luau"]},{"name":"MockConnection","className":"ModuleScript","filePaths":["src\\Studio\\MockConnection.luau"]},{"name":"MockIdentifiers","className":"ModuleScript","filePaths":["src\\Studio\\MockIdentifiers.luau"]}]},{"name":"Types","className":"ModuleScript","filePaths":["src\\Types.luau"]},{"name":"Utilities","className":"Folder","children":[{"name":"NetworkUtils","className":"ModuleScript","filePaths":["src\\Utilities\\NetworkUtils.luau"]},{"name":"Output","className":"ModuleScript","filePaths":["src\\Utilities\\Output.luau"]},{"name":"RecycledSpawn","className":"ModuleScript","filePaths":["src\\Utilities\\RecycledSpawn.luau"]},{"name":"isEditMode","className":"ModuleScript","filePaths":["src\\Utilities\\isEditMode.luau"]},{"name":"tostringData","className":"ModuleScript","filePaths":["src\\Utilities\\tostringData.luau"]}]},{"name":"version","className":"ModuleScript","filePaths":["src\\version.luau"]}]}]},{"name":"benches","className":"Folder","children":[{"name":"Hex.bench","className":"ModuleScript","filePaths":["benchmarks\\Hex.bench.luau"]}]},{"name":"framework","className":"ModuleScript","filePaths":["testing/framework\\init.luau"],"children":[{"name":"bootstrapper","className":"ModuleScript","filePaths":["testing/framework\\bootstrapper.luau"]},{"name":"expect","className":"ModuleScript","filePaths":["testing/framework\\expect.luau"]}]}]},{"name":"ServerScriptService","className":"ServerScriptService","children":[{"name":"featureTests","className":"Script","filePaths":["testing/tests/server\\featureTests\\init.server.luau"]}]},{"name":"StarterPlayer","className":"StarterPlayer","children":[{"name":"StarterPlayerScripts","className":"StarterPlayerScripts","children":[{"name":"featureTests","className":"LocalScript","filePaths":["testing/tests/client\\featureTests\\init.client.luau"]}]}]}]} \ No newline at end of file diff --git a/src/Client/ClientBridge.luau b/src/Client/ClientBridge.luau index e221f69..7e4d96f 100644 --- a/src/Client/ClientBridge.luau +++ b/src/Client/ClientBridge.luau @@ -260,7 +260,7 @@ function clientBridgePrototype:InvokeServerAsync(content: any) end if (reply :: {})[1] == ClientIdentifiers.ref("REQUEST", 3, false) and (reply :: {})[2] == id then connection() - task.spawn(thread, (reply :: {})[2]) + task.spawn(thread, (reply :: {})[3]) end end) return coroutine.yield() diff --git a/src/ExportedTypes.luau b/src/ExportedTypes.luau new file mode 100644 index 0000000..b6d9d39 --- /dev/null +++ b/src/ExportedTypes.luau @@ -0,0 +1,6 @@ +local PublicTypes = require(script.Parent.PublicTypes) + +export type ServerBridge = PublicTypes.ServerBridge +export type ClientBridge = PublicTypes.ClientBridge + +return nil diff --git a/src/PublicTypes.luau b/src/PublicTypes.luau index 88947e2..2773c7a 100644 --- a/src/PublicTypes.luau +++ b/src/PublicTypes.luau @@ -1,31 +1,31 @@ --!strict local Types = require(script.Parent.Types) -type ServerBridge = { +export type ServerBridge = { Fire: ( - self: ServerBridge, + self: ServerBridge, target: Player | (Types.AllPlayerContainer | Types.SetPlayerContainer), - content: Types.Content + content: send ) -> (), Connect: ( - self: ServerBridge, + self: ServerBridge, callback: (player: Player, content: Types.Content?) -> (), name: string? ) -> Connection, - Once: (self: ServerBridge, callback: (player: Player, content: Types.Content?) -> ()) -> (), - Wait: (self: ServerBridge, callback: (player: Player, content: Types.Content?) -> ()) -> (Player, Types.Content?), + Once: (self: ServerBridge, callback: (player: Player, content: Types.Content?) -> ()) -> (), + Wait: (self: ServerBridge) -> (Player, Types.Content?), OnServerInvoke: ((player: Player, content: Types.Content) -> ...any)?, RateLimitActive: boolean, Logging: boolean, } -type ClientBridge = { - Fire: (self: ClientBridge, content: any?) -> (), - Connect: (self: ClientBridge, callback: (content: Types.Content?) -> (), name: string?) -> Connection, - Once: (self: ClientBridge, callback: (content: Types.Content?) -> ()) -> (), - Wait: (self: ClientBridge, callback: (content: Types.Content?) -> ()) -> Types.Content?, +export type ClientBridge = { + Fire: (self: ClientBridge, content: send) -> (), + Connect: (self: ClientBridge, callback: (content: receive) -> (), name: string?) -> Connection, + Once: (self: ClientBridge, callback: (content: receive) -> ()) -> (), + Wait: (self: ClientBridge, callback: (content: receive) -> ()) -> receive, - InvokeServerAsync: (self: ClientBridge, content: any?) -> ...Types.Content?, + InvokeServerAsync: (self: ClientBridge, content: send) -> receive, Logging: boolean, } @@ -34,13 +34,13 @@ type Connection = { Disconnect: () -> (), } -export type Bridge = ServerBridge & ClientBridge +export type Bridge = ServerBridge & ClientBridge export type BridgeNet2 = { ReferenceBridge: (name: string) -> Bridge, - ClientBridge: (name: string) -> ClientBridge, - ServerBridge: (name: string) -> ServerBridge, + ClientBridge: (name: string) -> ClientBridge, + ServerBridge: (name: string) -> ServerBridge, ReferenceIdentifier: (name: string, maxWaitTime: number?) -> Types.Identifier, diff --git a/src/Server/ServerBridge.luau b/src/Server/ServerBridge.luau index e5c79d8..aefac6c 100644 --- a/src/Server/ServerBridge.luau +++ b/src/Server/ServerBridge.luau @@ -78,20 +78,24 @@ function serverBridgePrototype:Connect(callback: (player: Player, content: Types end if self.RateLimitActive then + -- get the current second + local thisSecond = math.round(os.clock() - os.clock() % 1) + if self._rateMap[player] ~= nil then - local currentCount: number = self._rateMap[player] - self._rateMap[player] = currentCount + 1 - else - self._rateMap[player] = 1 - end + local lastSecond = self._rateMap[player][1] or 0 - task.delay(1, function() - local currentCount: number = self._rateMap[player] + if lastSecond ~= thisSecond then + self._rateMap[player][2] = 0 - self._rateMap[player] = math.min(0, currentCount - 1) - end) + self._rateMap[player][1] = thisSecond + else + self._rateMap[player][2] += 1 + end + else + self._rateMap[player] = { thisSecond, 1 } + end - if self._rateMap[player] >= self._maxRate then + if self._rateMap[player][2] >= self._maxRate then if not self._overflowFunction(player) then return end @@ -316,7 +320,7 @@ return function(name: string) -- Rate limiting RateLimitActive = false, _maxRate = 500, - _rateMap = {} :: { [Player]: number }, + _rateMap = {} :: { [Player]: { number } }, _overflowFunction = function() return false end, diff --git a/src/init.luau b/src/init.luau index df9b153..6b2f811 100644 --- a/src/init.luau +++ b/src/init.luau @@ -109,13 +109,14 @@ local BridgeNet2 = { Players = Server.playerContainers().Players, ReferenceBridge = if isServer then Server.makeBridge else Client.makeBridge, - ServerBridge = if isServer then Server.makeBridge else nil, - ClientBridge = if not isServer then Client.makeBridge else nil, + Types = script.ExportedTypes, + HandleInvalidPlayer = function(handler: (player: Player) -> ()) Output.fatalAssert(isServer, "Cannot call from client") + Server.invalidPlayerhandler(handler) end, diff --git a/src/version.luau b/src/version.luau index 9599d96..bccc689 100644 --- a/src/version.luau +++ b/src/version.luau @@ -1 +1 @@ -return "0.5.7" +return "1.0.0" diff --git a/wally.lock b/wally.lock index a479c0b..cba7977 100644 --- a/wally.lock +++ b/wally.lock @@ -4,7 +4,7 @@ registry = "test" [[package]] name = "ffrostflame/bridgenet2" -version = "0.5.5" +version = "0.5.6" dependencies = [["RemotePacketSizeCounter", "pysephwasntavailable/remotepacketsizecounter@2.1.0"], ["TableKit", "ffrostflame/tablekit@0.2.4"], ["wallyInstanceManager", "ffrostflame/wally-instance-manager@0.1.0"]] [[package]] diff --git a/wally.toml b/wally.toml index 72feb29..e7d6d20 100644 --- a/wally.toml +++ b/wally.toml @@ -1,6 +1,6 @@ [package] name = "ffrostflame/bridgenet2" -version = "0.5.6" +version = "1.0.0" registry = "https://github.com/UpliftGames/wally-index" realm = "shared" description = "The successor to BridgeNet, BridgeNet2 is a blazing-fast networking library designed for scale and performance."