diff --git a/Warp.rbxm b/Warp.rbxm index d040501..8dbee97 100644 Binary files a/Warp.rbxm and b/Warp.rbxm differ diff --git a/src/Index/Client/ClientProcess.luau b/src/Index/Client/ClientProcess.luau index 5d43449..72200d8 100644 --- a/src/Index/Client/ClientProcess.luau +++ b/src/Index/Client/ClientProcess.luau @@ -106,6 +106,7 @@ function ClientProcess.start() table.clear(data) end for Identifier: string, data: any in clientQueue do + local callback = clientCallback[Identifier] or nil if #data > 0 then if clientRatelimit[Identifier](#data) then ReliableEvent:FireServer(Buffer.revert(Identifier), data) @@ -126,11 +127,11 @@ function ClientProcess.start() table.clear(incoming_cache[Identifier]) end end - if clientCallback[Identifier] then + if callback then if #queueIn[Identifier] > 0 then for _, packedDatas: any in queueIn[Identifier] do if #packedDatas == 0 then continue end - for _, fn: any in clientCallback[Identifier] do + for _, fn: any in callback do for i=1,math.min(1e3, #packedDatas) do Spawn(fn, table.unpack(packedDatas[i] or {})) end @@ -141,7 +142,7 @@ function ClientProcess.start() if #queueInRequest[1][Identifier] > 0 then for idx, packetDatas: any in queueInRequest[1][Identifier] do if #packetDatas == 0 then continue end - for _, fn: any in clientCallback[Identifier] do + for _, fn: any in callback do for i=1,math.min(1e3, #packetDatas) do local packetData = packetDatas[i] if not packetData then continue end diff --git a/src/Index/Client/ClientProcess/Logger.luau b/src/Index/Client/ClientProcess/Logger.luau new file mode 100644 index 0000000..b6de03d --- /dev/null +++ b/src/Index/Client/ClientProcess/Logger.luau @@ -0,0 +1,32 @@ +--!strict +local Logger = {} +local Logs: { + [string]: { + [string]: string + } +} = {} +local logging: { + [string]: boolean +} = {} + +local now = tick() + +function Logger.write(Identifier: string, text: string, log: boolean?) + if not Logs[Identifier] then + Logs[Identifier] = {} + end + if log ~= nil then + logging[Identifier] = log + end + now = tick() + Logs[Identifier][tostring(now)] = text + if logging[Identifier] then + print(`[{now}] ->`, text) + end +end + +function Logger.read(Identifier: string) + return Logs[Identifier] +end + +return Logger \ No newline at end of file diff --git a/src/Index/Client/ClientProcess/init.luau b/src/Index/Client/ClientProcess/init.luau new file mode 100644 index 0000000..1f67e51 --- /dev/null +++ b/src/Index/Client/ClientProcess/init.luau @@ -0,0 +1,253 @@ +--!native +--!strict +--!optimize 2 +local ClientProcess = {} + +local RunService = game:GetService("RunService") +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) +local Buffer = require(Util.Buffer) +local Logger = require(script.Logger) + +local clientRatelimit: Type.StoredRatelimit = {} +local clientQueue: Type.QueueMap = {} +local unreliableClientQueue: Type.QueueMap = {} +local clientCallback: Type.CallbackMap = {} +local clientRequestQueue: Type.QueueMap = {} + +local queueIn: { + [string]: {any} +} = {} +local queueInRequest: { + [number]: { + [string]: { + any + } + } +} = {} +local queueOutRequest: { + [number]: { + [string]: { + any + } + } +} = {} +local incoming_cache: { + [string]: { + any + } +} = {} +local logger: { + [string]: boolean +} = {} + +queueInRequest[1] = {} +queueInRequest[2] = {} +queueOutRequest[1] = {} +queueOutRequest[2] = {} + +local ReliableEvent = Event.Reliable +local UnreliableEvent = Event.Unreliable +local RequestEvent = Event.Request + +function ClientProcess.insertQueue(Identifier: string, reliable: boolean, ...: any) + if not reliable then + table.insert(unreliableClientQueue[Identifier], { ... }) + return + end + table.insert(clientQueue[Identifier], { ... }) +end + +function ClientProcess.insertRequest(Identifier: string, timeout: number, ...: any) + local yieldThread: thread, start = coroutine.running(), os.clock() + local cancel = task.delay(timeout, function() + task.spawn(yieldThread, nil) + end) + table.insert(clientRequestQueue[Identifier], { 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 ClientProcess.add(Identifier: any, originId: string) + if not clientQueue[Identifier] then + clientRatelimit[Identifier] = RateLimit.create(originId) + clientQueue[Identifier] = {} + unreliableClientQueue[Identifier] = {} + clientRequestQueue[Identifier] = {} + clientCallback[Identifier] = {} + + queueOutRequest[1][Identifier] = {} + queueOutRequest[2][Identifier] = {} + queueInRequest[1][Identifier] = {} + queueInRequest[2][Identifier] = {} + queueIn[Identifier] = {} + end +end + +function ClientProcess.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 ClientProcess.getlogs(Identifier: string) + return Logger.read(Identifier) +end + +function ClientProcess.addCallback(Identifier: string, key: string, callback) + clientCallback[Identifier][key] = callback + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: change -> new callback added.`) + end +end + +function ClientProcess.removeCallback(Identifier: string, key: string) + clientCallback[Identifier][key] = nil + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: change -> removed a callback.`) + end +end + +function ClientProcess.start() + RunService.PostSimulation:Connect(function() + for Identifier: string, data: any in unreliableClientQueue do + if #data == 0 then continue end + if clientRatelimit[Identifier](#data) then + UnreliableEvent:FireServer(Buffer.revert(Identifier), data) + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#data} data.`) + end + end + table.clear(data) + end + for Identifier: string, data: any in clientQueue do + local callback = clientCallback[Identifier] or nil + 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 + table.clear(data) + end + if #clientRequestQueue[Identifier] > 0 then + for _, requestData in clientRequestQueue[Identifier] do + if not requestData[3] then continue end + table.insert(queueOutRequest[1][Identifier], { requestData[1], requestData[3] }) + table.remove(requestData, #requestData) + end + end + if incoming_cache[Identifier] then + for _, packet in incoming_cache[Identifier] do + if not queueIn[Identifier] then continue end + table.insert(queueIn[Identifier], table.clone(packet)) + table.clear(incoming_cache[Identifier]) + end + end + if callback then + if #queueIn[Identifier] > 0 then + for _, packedDatas: any in queueIn[Identifier] do + if #packedDatas == 0 then continue end + for _, fn: any in callback do + for i=1,math.min(1e3, #packedDatas) do + Spawn(fn, table.unpack(packedDatas[i] or {})) + end + end + end + table.clear(queueIn[Identifier]) + end + if #queueInRequest[1][Identifier] > 0 then + for idx, packetDatas: any in queueInRequest[1][Identifier] do + if #packetDatas == 0 then continue end + for _, fn: any in callback do + for i=1,math.min(1e3, #packetDatas) do + local packetData = packetDatas[i] + if not packetData then continue end + Spawn(function() + local requestReturn = { fn(table.unpack(packetData[2])) } + table.insert(queueOutRequest[2][Identifier], { packetData[1], requestReturn }) + end) + end + end + end + table.clear(queueInRequest[1][Identifier]) + end + if #queueInRequest[2][Identifier] > 0 then + for _, packetDatas: any in queueInRequest[2][Identifier] do + for _, packetData in packetDatas do + if #packetData == 1 then continue end + for y=1, math.min(1e3, #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 + table.clear(queueInRequest[2][Identifier]) + end + 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 + table.clear(queueOutRequest[1][Identifier]) + 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 + table.clear(queueOutRequest[2][Identifier]) + end + end) + local function onClientNetworkReceive(Identifier: any, data: any) + if not Identifier or not data then return end + Identifier = Buffer.convert(Identifier) + if not queueIn[Identifier] then + queueIn[Identifier] = {} + end + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: in -> net -> {#data} data.`) + end + if not clientCallback[Identifier] then + if not incoming_cache[Identifier] then + incoming_cache[Identifier] = {} + end + table.insert(incoming_cache[Identifier], data) + return + end + table.insert(queueIn[Identifier], data) + end + ReliableEvent.OnClientEvent:Connect(onClientNetworkReceive) + UnreliableEvent.OnClientEvent:Connect(onClientNetworkReceive) + RequestEvent.OnClientEvent:Connect(function(Identifier: any, action: string, data) + if not Identifier or not data then return end + Identifier = Buffer.convert(Identifier) + if action == "\1" then + table.insert(queueInRequest[1][Identifier], data) + else + table.insert(queueInRequest[2][Identifier], data) + end + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: in -> request -> {#data} data.`) + end + end) +end + +return ClientProcess \ No newline at end of file diff --git a/src/Index/Client/Index.luau b/src/Index/Client/Index.luau index a5c3f7e..fc925ff 100644 --- a/src/Index/Client/Index.luau +++ b/src/Index/Client/Index.luau @@ -13,10 +13,10 @@ local Key = require(Util.Key) local Serdes = require(Util.Serdes) local Buffer = require(Util.Buffer) -function Client.new(Identifier: string) +function Client.new(Identifier: string, yieldWait: number?) local self = setmetatable({}, Client) self._buffer = Buffer.new() - self._buffer:wu8(Serdes(Identifier)) + self._buffer:wu8(Serdes(Identifier, yieldWait)) self.id = Buffer.convert(self._buffer:build()) self.fn = {} self.IsConnected = false @@ -25,6 +25,13 @@ function Client.new(Identifier: string) return self end +function Client:Logging(store: boolean, opt: boolean) + ClientProcess.logger(self.id, store, opt) + return function() + return ClientProcess.getlogs(self.id) + end +end + function Client:Fire(reliable: boolean,...: any) ClientProcess.insertQueue(self.id, reliable, ...) end diff --git a/src/Index/Server/Index.luau b/src/Index/Server/Index.luau index 48785a0..7202fd8 100644 --- a/src/Index/Server/Index.luau +++ b/src/Index/Server/Index.luau @@ -26,6 +26,13 @@ function Server.new(Identifier: string, rateLimit: Type.rateLimitArg?) return self end +function Server:Logging(store: boolean, opt: boolean) + ServerProcess.logger(self.id, store, opt) + return function() + return ServerProcess.getlogs(self.id) + end +end + function Server:Fire(reliable: boolean, player: Player, ...: any) ServerProcess.insertQueue(self.id, reliable, player, ...) end diff --git a/src/Index/Server/ServerProcess/Logger.luau b/src/Index/Server/ServerProcess/Logger.luau new file mode 100644 index 0000000..b6de03d --- /dev/null +++ b/src/Index/Server/ServerProcess/Logger.luau @@ -0,0 +1,32 @@ +--!strict +local Logger = {} +local Logs: { + [string]: { + [string]: string + } +} = {} +local logging: { + [string]: boolean +} = {} + +local now = tick() + +function Logger.write(Identifier: string, text: string, log: boolean?) + if not Logs[Identifier] then + Logs[Identifier] = {} + end + if log ~= nil then + logging[Identifier] = log + end + now = tick() + Logs[Identifier][tostring(now)] = text + if logging[Identifier] then + print(`[{now}] ->`, text) + end +end + +function Logger.read(Identifier: string) + return Logs[Identifier] +end + +return Logger \ No newline at end of file diff --git a/src/Index/Server/ServerProcess.luau b/src/Index/Server/ServerProcess/init.luau similarity index 85% rename from src/Index/Server/ServerProcess.luau rename to src/Index/Server/ServerProcess/init.luau index 3614246..f13e716 100644 --- a/src/Index/Server/ServerProcess.luau +++ b/src/Index/Server/ServerProcess/init.luau @@ -13,6 +13,7 @@ local Spawn = require(Util.Spawn) local Key = require(Util.Key) local RateLimit = require(Util.RateLimit) local Buffer = require(Util.Buffer) +local Logger = require(script.Logger) local serverQueue: Type.QueueMap = {} local unreliableServerQueue: Type.QueueMap = {} @@ -43,6 +44,10 @@ local queueOutRequest: { } } } = {} +local logger: { + [string]: boolean +} = {} + queueInRequest[1] = {} queueInRequest[2] = {} queueOutRequest[1] = {} @@ -131,12 +136,27 @@ function ServerProcess.add(Identifier: string, originId: string, ratelimit: Type end end +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 + function ServerProcess.addCallback(Identifier: string, key: string, callback) serverCallback[Identifier][key] = callback + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: change -> new callback added.`) + end end function ServerProcess.removeCallback(Identifier: string, key: string) serverCallback[Identifier][key] = nil + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: change -> removed a callback.`) + end end function ServerProcess.start() @@ -145,6 +165,9 @@ function ServerProcess.start() for player: Player, data: any in players do if #data == 0 then continue end UnreliableEvent:FireClient(player, Buffer.revert(Identifier), data) + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: out -> unreliable -> {#data} data.`) + end table.clear(data) end end @@ -153,10 +176,14 @@ function ServerProcess.start() for Identifier: string, data: any in queueOut[player] do if #data == 0 then continue end ReliableEvent:FireClient(player, Buffer.revert(Identifier), data) + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: out -> reliable -> {#data} data.`) + end table.clear(data) end end for Identifier: string, players in serverQueue do + local callback = serverCallback[Identifier] or nil for player: Player, data in players do if #data > 0 and queueOut[player] then queueOut[player][Identifier] = table.clone(data) @@ -169,11 +196,11 @@ function ServerProcess.start() table.remove(requestData, #requestData) end end - if serverCallback[Identifier] then + if callback then if #queueIn[Identifier][player] > 0 then for _, packedDatas: any in queueIn[Identifier][player] do if #packedDatas == 0 then continue end - for _, fn: any in serverCallback[Identifier] do + for _, fn: any in callback do for i=1,math.min(1e3, #packedDatas) do Spawn(fn, player, table.unpack(packedDatas[i] or {})) end @@ -184,7 +211,7 @@ function ServerProcess.start() if #queueInRequest[1][Identifier][player] > 0 then for idx, packetDatas: any in queueInRequest[1][Identifier][player] do if #packetDatas == 0 then continue end - for _, fn: any in serverCallback[Identifier] do + for _, fn: any in callback do for i=1,math.min(1e3, #packetDatas) do local packetData = packetDatas[i] if not packetData then continue end @@ -218,11 +245,17 @@ function ServerProcess.start() for player: Player, requestsData: any in queueOutRequest[1][Identifier] do if #requestsData == 0 then continue end RequestEvent:FireClient(player, Buffer.revert(Identifier), "\1", requestsData) + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: out -> request -> {#requestsData} data.`) + end table.clear(requestsData) end for player: Player, toReturnDatas: any in queueOutRequest[2][Identifier] do if #toReturnDatas == 0 then continue end RequestEvent:FireClient(player, Buffer.revert(Identifier), "\0", toReturnDatas) + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: out -> return request -> {#toReturnDatas} data.`) + end table.clear(toReturnDatas) end end @@ -241,6 +274,9 @@ function ServerProcess.start() if not queueIn[Identifier][player] then queueIn[Identifier][player] = {} end + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: in -> net -> {#data} data.`) + end table.insert(queueIn[Identifier][player], data) end ReliableEvent.OnServerEvent:Connect(onServerNetworkReceive) @@ -260,6 +296,9 @@ function ServerProcess.start() else table.insert(queueInRequest[2][Identifier][player], data) end + if logger[Identifier] then + task.defer(Logger.write, Identifier, `state: in -> request -> {#data} data.`) + end end) end diff --git a/src/Index/Signal/init.luau b/src/Index/Signal/init.luau index 5b7387c..567ab01 100644 --- a/src/Index/Signal/init.luau +++ b/src/Index/Signal/init.luau @@ -55,7 +55,7 @@ end function Signal:Fire(...: any): () for _, handle in self do - pcall(handle.fn, ...) + task.spawn(handle.fn, ...) end end diff --git a/src/Index/Type.luau b/src/Index/Type.luau index 0d3832e..79cbf04 100644 --- a/src/Index/Type.luau +++ b/src/Index/Type.luau @@ -13,6 +13,7 @@ export type Client = { DisconnectAll: (self: Client) -> (), Destroy: (self: Client) -> (), Wait: (self: Client) -> number, + Logging: (self: Client, store: boolean, opt: boolean) -> (), } export type Server = { @@ -25,6 +26,7 @@ export type Server = { DisconnectAll: (self: Server) -> (), Destroy: (self: Server) -> (), Wait: (self: Server) -> number, + Logging: (self: Server, store: boolean, opt: boolean) -> (), } export type Signal = { diff --git a/src/Index/Util/Assert.luau b/src/Index/Util/Assert.luau index c0932f3..ed9e790 100644 --- a/src/Index/Util/Assert.luau +++ b/src/Index/Util/Assert.luau @@ -1,4 +1,4 @@ --!strict return function(condition: (any), errorMessage: string?): () - if not (condition) then error(errorMessage, 2) end + if not (condition) then error(`Warp: {errorMessage}`, 2) end end \ No newline at end of file diff --git a/src/Index/Util/Buffer/Dedicated.luau b/src/Index/Util/Buffer/Dedicated.luau index 4860b69..552eb60 100644 --- a/src/Index/Util/Buffer/Dedicated.luau +++ b/src/Index/Util/Buffer/Dedicated.luau @@ -58,46 +58,55 @@ function DedicatedBuffer.build(self: any): buffer end function DedicatedBuffer.wi8(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 1) writei8(self.buffer, self.point, val) end function DedicatedBuffer.wi16(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 2) writei16(self.buffer, self.point, val) end function DedicatedBuffer.wi32(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 4) writei32(self.buffer, self.point, val) end function DedicatedBuffer.wu8(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 1) writeu8(self.buffer, self.point, val) end function DedicatedBuffer.wu16(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 2) writeu16(self.buffer, self.point, val) end function DedicatedBuffer.wu32(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 4) writeu32(self.buffer, self.point, val) end function DedicatedBuffer.wf32(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 4) writef32(self.buffer, self.point, val) end function DedicatedBuffer.wf64(self: any, val: number) + if not val then return end DedicatedBuffer.alloc(self, 8) writef64(self.buffer, self.point, val) end function DedicatedBuffer.wstring(self: any, val: string) + if not val then return end DedicatedBuffer.alloc(self, #val) writestring(self.buffer, self.point, val) end diff --git a/src/Index/Util/Key.luau b/src/Index/Util/Key.luau index 5ec0ed9..e807e73 100644 --- a/src/Index/Util/Key.luau +++ b/src/Index/Util/Key.luau @@ -1,4 +1,4 @@ --!strict return function(): number? - return tonumber(string.sub(tostring(Random.new():NextNumber()), 3, 6)) + return tonumber(string.sub(tostring(Random.new():NextNumber()), 3, 7)) -- 4 digits end \ No newline at end of file diff --git a/src/Index/Util/Serdes.luau b/src/Index/Util/Serdes.luau index d71743b..025fd68 100644 --- a/src/Index/Util/Serdes.luau +++ b/src/Index/Util/Serdes.luau @@ -5,19 +5,26 @@ local SerInt = 0 local Event = require(script.Parent.Parent.Event).Reliable local Assert = require(script.Parent.Assert) -return function(Identifier: string): number +return function(Identifier: string, timeout: number?): number Assert(typeof(Identifier) == "string", "Identifier must be a string type.") Assert(SerInt < 255, "reached max 255 identifiers.") if RunService:IsServer() then if not Event:GetAttribute(Identifier) then SerInt += 1 Event:SetAttribute(Identifier, SerInt) - --Event:SetAttribute(Identifier, string.pack("I1", SerInt)) -- I1 -> 255 max, I2 -> ~ 6.5e4 max. (SerInt) + --Event:SetAttribute(Identifier, string.pack("I1", SerInt)) -- I1 -> 255 max, I2 -> ~ 6.5e4 max. (SerInt), removed/disabled for buffer migration. end else - while not Event:GetAttribute(Identifier) do + local retreived = false + task.delay(timeout or 10, function() + if retreived then return end + retreived = true + error(`Serdes: {Identifier} is taking too long to retrieve, seems like not replicated on server.`, 2) + end) + while (not retreived) and (not Event:GetAttribute(Identifier)) do task.wait(0.5) end + retreived = true end return Event:GetAttribute(Identifier) end \ No newline at end of file diff --git a/src/Index/init.luau b/src/Index/init.luau index 35ced65..7197f5f 100644 --- a/src/Index/init.luau +++ b/src/Index/init.luau @@ -25,10 +25,10 @@ function Index.Server(Identifier: string, rateLimit: Type.rateLimitArg?): Type.S Assert(typeof(Identifier) == "string", `[Warp]: Identifier must be a string type, got {typeof(Identifier)}`) return require(Server.Index)(Identifier, rateLimit) :: Type.Server end -function Index.Client(Identifier: string): Type.Client +function Index.Client(Identifier: string, yieldWait: number?): Type.Client Assert(not IsServer, `[Warp]: Calling .Client({Identifier}) on server side (expected client side)`) Assert(typeof(Identifier) == "string", `[Warp]: Identifier must be a string type, got {typeof(Identifier)}`) - return require(Client.Index)(Identifier) :: Type.Client + return require(Client.Index)(Identifier, yieldWait) :: Type.Client end function Index.fromServerArray(arrays: { any }): Type.fromServerArray diff --git a/src/init.luau b/src/init.luau index fbaec6f..80607e0 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,5 +1,5 @@ -- Warp Library (@Eternity_Devs) --- version 1.0.8 +-- version 1.0.9 --!strict --!native --!optimize 2 diff --git a/wally.toml b/wally.toml index 15522a3..5adbc71 100644 --- a/wally.toml +++ b/wally.toml @@ -1,6 +1,6 @@ [package] name = "imezx/warp" -version = "1.0.8" +version = "1.0.9" registry = "https://github.com/UpliftGames/wally-index" realm = "shared" license = "MIT"