mirror of
https://github.com/imezx/Warp.git
synced 2026-06-02 12:18:32 +00:00
Compare commits
17 commits
1.1.0-pre5
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a27067c8df | ||
|
|
a6456af3e3 | ||
|
|
a21a1e964b | ||
|
|
677a13dcc1 | ||
|
|
61deb37bae | ||
|
|
f470f74b29 | ||
|
|
36137ea940 | ||
|
|
57f381d335 | ||
|
|
b425db5f0b | ||
|
|
847b76921a | ||
|
|
1834e01a24 | ||
|
|
0b9bc3d39c | ||
|
|
1f9ae004f4 | ||
|
|
597bfabb3d | ||
|
|
ce8cfeef5e | ||
|
|
39143db390 | ||
|
|
33477c4b74 |
13 changed files with 317 additions and 101 deletions
BIN
Warp.rbxm
BIN
Warp.rbxm
Binary file not shown.
|
|
@ -5,7 +5,7 @@ For efficient data serialization and schema definition with optimized packing.
|
||||||
## Getting the Buffer Object
|
## Getting the Buffer Object
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local Buffer = Warp.Buffer()
|
local Buffer = Warp.Buffer
|
||||||
```
|
```
|
||||||
|
|
||||||
## Schema System <Badge type="tip" text="v1.1" />
|
## Schema System <Badge type="tip" text="v1.1" />
|
||||||
|
|
@ -19,10 +19,9 @@ Define strict data schemas for optimized serialization and type safety.
|
||||||
-- Basic types
|
-- Basic types
|
||||||
"boolean",
|
"boolean",
|
||||||
"string",
|
"string",
|
||||||
"nil",
|
|
||||||
|
|
||||||
-- Numeric types
|
-- Numeric types
|
||||||
"u8", -- usigned-int
|
"u8", -- unsigned-int
|
||||||
"u16",
|
"u16",
|
||||||
"u32",
|
"u32",
|
||||||
"i8", -- signed-int
|
"i8", -- signed-int
|
||||||
|
|
@ -33,12 +32,28 @@ Define strict data schemas for optimized serialization and type safety.
|
||||||
"f64",
|
"f64",
|
||||||
|
|
||||||
-- Roblox types
|
-- Roblox types
|
||||||
"buffer"
|
"buffer",
|
||||||
"vector2", -- f16
|
"vector2", -- f16 x/y
|
||||||
"vector3", -- f16
|
"vector3", -- f16 x/y/z
|
||||||
"cframe", -- f32 & f16
|
"vector2f32", -- f32 x/y
|
||||||
"color3", -- u8
|
"vector3f32", -- f32 x/y/z
|
||||||
|
"vector2int16", -- i16 x/y
|
||||||
|
"vector3int16", -- i16 x/y/z
|
||||||
|
"cframe", -- f32 position + compressed rotation (f16)
|
||||||
|
"color3", -- u8 r/g/b
|
||||||
"color3f16",
|
"color3f16",
|
||||||
|
"udim",
|
||||||
|
"udim2",
|
||||||
|
"rect",
|
||||||
|
"ray",
|
||||||
|
"numberrange",
|
||||||
|
"colorsequence",
|
||||||
|
"numbersequence",
|
||||||
|
"brickcolor",
|
||||||
|
"tweeninfo",
|
||||||
|
"physicalproperties",
|
||||||
|
"font",
|
||||||
|
"datetime",
|
||||||
"instance",
|
"instance",
|
||||||
|
|
||||||
-- other types
|
-- other types
|
||||||
|
|
@ -49,6 +64,10 @@ Define strict data schemas for optimized serialization and type safety.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: info
|
||||||
|
there is no standalone `"nil"` schema type. To represent a value that can be `nil`, wrap it with `"optional"` (e.g. `Buffer.Schema.optional(Buffer.Schema.u16)`).
|
||||||
|
:::
|
||||||
|
|
||||||
## Custom Datatypes
|
## Custom Datatypes
|
||||||
|
|
||||||
### `.custom_datatype`
|
### `.custom_datatype`
|
||||||
|
|
@ -64,7 +83,7 @@ Define strict data schemas for optimized serialization and type safety.
|
||||||
```
|
```
|
||||||
|
|
||||||
```luau [Example]
|
```luau [Example]
|
||||||
local Buffer = Warp.Buffer()
|
local Buffer = Warp.Buffer
|
||||||
|
|
||||||
-- # this custom datatype must be registered on both server & client side
|
-- # this custom datatype must be registered on both server & client side
|
||||||
Buffer.Schema.custom_datatype("u64", {}, function(w: Buffer.Writer, value: any) -- just for reference
|
Buffer.Schema.custom_datatype("u64", {}, function(w: Buffer.Writer, value: any) -- just for reference
|
||||||
|
|
@ -94,7 +113,7 @@ Create a new buffer writer for serializing data.
|
||||||
```
|
```
|
||||||
|
|
||||||
```luau [Example]
|
```luau [Example]
|
||||||
local Buffer = Warp.Buffer()
|
local Buffer = Warp.Buffer
|
||||||
local writer = Buffer.createWriter(256) -- Pre-allocate 256 bytes
|
local writer = Buffer.createWriter(256) -- Pre-allocate 256 bytes
|
||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
@ -111,7 +130,7 @@ Build the final buffer for transmission.
|
||||||
```
|
```
|
||||||
|
|
||||||
```luau [Example]
|
```luau [Example]
|
||||||
local Buffer = Warp.Buffer()
|
local Buffer = Warp.Buffer
|
||||||
local writer = Buffer.createWriter()
|
local writer = Buffer.createWriter()
|
||||||
|
|
||||||
-- Write some data
|
-- Write some data
|
||||||
|
|
@ -136,7 +155,7 @@ Build the final buffer with instance references for transmission.
|
||||||
```
|
```
|
||||||
|
|
||||||
```luau [Example]
|
```luau [Example]
|
||||||
local Buffer = Warp.Buffer()
|
local Buffer = Warp.Buffer
|
||||||
local writer = Buffer.createWriter()
|
local writer = Buffer.createWriter()
|
||||||
|
|
||||||
-- Write some data with instances
|
-- Write some data with instances
|
||||||
|
|
@ -161,7 +180,7 @@ Reset a writer for reuse, clearing all data.
|
||||||
```
|
```
|
||||||
|
|
||||||
```luau [Example]
|
```luau [Example]
|
||||||
local Buffer = Warp.Buffer()
|
local Buffer = Warp.Buffer
|
||||||
local writer = Buffer.createWriter()
|
local writer = Buffer.createWriter()
|
||||||
|
|
||||||
-- Use writer for first batch
|
-- Use writer for first batch
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ this is optional and conditional, you may have to use this if you had a problem
|
||||||
```luau [Variable]
|
```luau [Variable]
|
||||||
(
|
(
|
||||||
namespaces: { string },
|
namespaces: { string },
|
||||||
) -> Connection
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
```luau [Example]
|
```luau [Example]
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ local Players = game:GetService("Players")
|
||||||
local Warp = require(path.to.warp).Client()
|
local Warp = require(path.to.warp).Client()
|
||||||
local Schemas = require(path.to.schemas)
|
local Schemas = require(path.to.schemas)
|
||||||
|
|
||||||
|
Warp.awaitReady() -- this is optional, but recommended if facing any issues with race-condition, or remotes not registered
|
||||||
|
|
||||||
-- Use schemas
|
-- Use schemas
|
||||||
for eventName, schema in Schemas do
|
for eventName, schema in Schemas do
|
||||||
Warp.useSchema(eventName, schema)
|
Warp.useSchema(eventName, schema)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name = "eternitydev/warp"
|
name = "eternitydev/warp"
|
||||||
version = "1.1.0-pre4"
|
version = "1.1.0-pre7"
|
||||||
description = "A rapidly-fast & powerful networking library."
|
description = "A rapidly-fast & powerful networking library."
|
||||||
authors = ["eternitydev"]
|
authors = ["eternitydev"]
|
||||||
repository = "https://github.com/imezx/Warp"
|
repository = "https://github.com/imezx/Warp"
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"name":"warp","className":"ModuleScript","filePaths":["src/init.luau","default.project.json"],"children":[{"name":"Client","className":"ModuleScript","filePaths":["src/Client/init.luau"]},{"name":"Replication","className":"ModuleScript","filePaths":["src/Replication/init.luau"]},{"name":"Server","className":"ModuleScript","filePaths":["src/Server/init.luau"]},{"name":"Util","className":"Folder","children":[{"name":"Buffer","className":"ModuleScript","filePaths":["src/Util/Buffer/init.luau"]},{"name":"Identifier","className":"ModuleScript","filePaths":["src/Util/Identifier.luau"]},{"name":"Thread","className":"ModuleScript","filePaths":["src/Util/Thread.luau"]}]}]}
|
{"name":"warp","className":"ModuleScript","filePaths":["src/init.luau","default.project.json"],"children":[{"name":"Client","className":"ModuleScript","filePaths":["src/Client/init.luau"]},{"name":"Replication","className":"ModuleScript","filePaths":["src/Replication/init.luau"]},{"name":"Server","className":"ModuleScript","filePaths":["src/Server/init.luau"]},{"name":"Util","className":"Folder","children":[{"name":"Buffer","className":"ModuleScript","filePaths":["src/Util/Buffer/init.luau"]},{"name":"Identifier","className":"ModuleScript","filePaths":["src/Util/Identifier.luau"]},{"name":"Thread","className":"ModuleScript","filePaths":["src/Util/Thread.luau"]},{"name":"Xor","className":"ModuleScript","filePaths":["src/Util/Xor.luau"]}]}]}
|
||||||
|
|
@ -3,12 +3,14 @@
|
||||||
--@EternityDev
|
--@EternityDev
|
||||||
local Client = {}
|
local Client = {}
|
||||||
|
|
||||||
local RunService = game:GetService("RunService")
|
|
||||||
local Thread = require("./Util/Thread")
|
local Thread = require("./Util/Thread")
|
||||||
local Buffer = require("./Util/Buffer")
|
local Buffer = require("./Util/Buffer")
|
||||||
local Replication = require("./Replication")
|
local Replication = require("./Replication")
|
||||||
local Event: RemoteEvent = script.Parent:WaitForChild("Event")
|
local Xor = require("./Util/Xor")
|
||||||
local UnreliableEvent: UnreliableRemoteEvent = script.Parent:WaitForChild("UnreliableEvent")
|
|
||||||
|
local RunService = game:GetService("RunService")
|
||||||
|
local Event: RemoteEvent = script.Parent:WaitForChild("Event") :: RemoteEvent
|
||||||
|
local UnreliableEvent: UnreliableRemoteEvent = script.Parent:WaitForChild("UnreliableEvent") :: UnreliableRemoteEvent
|
||||||
local deltaT: number, cycle: number = 0, 1 / 61
|
local deltaT: number, cycle: number = 0, 1 / 61
|
||||||
local writer: Buffer.Writer = Buffer.createWriter()
|
local writer: Buffer.Writer = Buffer.createWriter()
|
||||||
|
|
||||||
|
|
@ -26,6 +28,7 @@ local queueUnreliableEvent: { { any } } = {}
|
||||||
local eventListeners: { [number]: { Event } } = {}
|
local eventListeners: { [number]: { Event } } = {}
|
||||||
local eventSchemas: { [number]: Buffer.SchemaType } = {}
|
local eventSchemas: { [number]: Buffer.SchemaType } = {}
|
||||||
|
|
||||||
|
local lastDelta: { [number]: { any } } = {}
|
||||||
local pendingInvokes: { [string]: thread } = {}
|
local pendingInvokes: { [string]: thread } = {}
|
||||||
local invokeId = 0
|
local invokeId = 0
|
||||||
|
|
||||||
|
|
@ -48,7 +51,7 @@ end
|
||||||
--@remoteName string
|
--@remoteName string
|
||||||
--@fn function
|
--@fn function
|
||||||
-- Connect to an event to receive incoming data from the server.
|
-- Connect to an event to receive incoming data from the server.
|
||||||
Client.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): Connection
|
Client.Connect = function(remoteName: string, fn: (...any?) -> ...any?): Connection
|
||||||
local id = Replication.get_id[remoteName]
|
local id = Replication.get_id[remoteName]
|
||||||
if not id then
|
if not id then
|
||||||
warn(`[Warp]: ".Connect"::"{remoteName}" does not exist, likely its not registered on the server yet.`)
|
warn(`[Warp]: ".Connect"::"{remoteName}" does not exist, likely its not registered on the server yet.`)
|
||||||
|
|
@ -165,17 +168,16 @@ end
|
||||||
|
|
||||||
if RunService:IsClient() then
|
if RunService:IsClient() then
|
||||||
local function processIncoming(b: buffer, ref: { Instance }?, handleInvokes: boolean)
|
local function processIncoming(b: buffer, ref: { Instance }?, handleInvokes: boolean)
|
||||||
if type(b) ~= "buffer" then
|
if type(b) ~= "buffer" then return end
|
||||||
return
|
local decoded: buffer = handleInvokes and Xor.decodeClient(b) or b
|
||||||
end
|
local contents = Buffer.readEvents(decoded, ref, eventSchemas)
|
||||||
local contents = Buffer.readEvents(b, ref, eventSchemas)
|
|
||||||
for _, content in contents do
|
for _, content in contents do
|
||||||
local remote = content[1]
|
local remote = content[1]
|
||||||
local content = content[2]
|
local args = content[2]
|
||||||
if handleInvokes then
|
if handleInvokes then
|
||||||
if remote == 0 then
|
if remote == 0 then
|
||||||
local id = content[1]
|
local id = args[1]
|
||||||
local results = content[2]
|
local results = args[2]
|
||||||
local pending = pendingInvokes[id]
|
local pending = pendingInvokes[id]
|
||||||
if pending then
|
if pending then
|
||||||
task.spawn(pending :: any, table.unpack(results))
|
task.spawn(pending :: any, table.unpack(results))
|
||||||
|
|
@ -184,17 +186,12 @@ if RunService:IsClient() then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
if remote == 1 then
|
if remote == 1 then
|
||||||
local remoteName = content[1]
|
local remoteName, id, rargs = args[1], args[2], args[3]
|
||||||
local id = content[2]
|
|
||||||
local args = content[3]
|
|
||||||
local connections = eventListeners[remoteName]
|
local connections = eventListeners[remoteName]
|
||||||
if connections and #connections > 0 then
|
if connections and #connections > 0 then
|
||||||
Thread(function()
|
Thread(function()
|
||||||
local results = { connections[1].c(table.unpack(args)) }
|
local results = { connections[1].c(table.unpack(rargs)) }
|
||||||
table.insert(queueEvent, {
|
table.insert(queueEvent, { 1, { id, results } :: any })
|
||||||
1,
|
|
||||||
{ id, results } :: any,
|
|
||||||
})
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
continue
|
continue
|
||||||
|
|
@ -203,7 +200,7 @@ if RunService:IsClient() then
|
||||||
local connections = eventListeners[remote]
|
local connections = eventListeners[remote]
|
||||||
if connections then
|
if connections then
|
||||||
for _, connection in connections do
|
for _, connection in connections do
|
||||||
Thread(connection.c, table.unpack(content))
|
Thread(connection.c :: any, table.unpack(args))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -219,21 +216,20 @@ if RunService:IsClient() then
|
||||||
|
|
||||||
RunService.PostSimulation:Connect(function(d: number)
|
RunService.PostSimulation:Connect(function(d: number)
|
||||||
deltaT += d
|
deltaT += d
|
||||||
if deltaT < cycle then
|
if deltaT < cycle then return end
|
||||||
return
|
|
||||||
end
|
|
||||||
deltaT = 0
|
deltaT = 0
|
||||||
|
|
||||||
-- reliable
|
--reliable
|
||||||
if #queueEvent > 0 then
|
if #queueEvent > 0 then
|
||||||
Buffer.writeEvents(writer, queueEvent, eventSchemas)
|
Buffer.writeEvents(writer, queueEvent, eventSchemas)
|
||||||
do
|
do
|
||||||
local buf, ref = Buffer.buildWithRefs(writer)
|
local buf, ref = Buffer.buildWithRefs(writer)
|
||||||
|
local encoded = Xor.encodeClient(buf)
|
||||||
Buffer.reset(writer)
|
Buffer.reset(writer)
|
||||||
if not ref or #ref == 0 then
|
if not ref or #ref == 0 then
|
||||||
Event:FireServer(buf)
|
Event:FireServer(encoded)
|
||||||
else
|
else
|
||||||
Event:FireServer(buf, ref)
|
Event:FireServer(encoded, ref)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.clear(queueEvent)
|
table.clear(queueEvent)
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ if RunService:IsClient() or RunService:IsRunMode() then
|
||||||
-- wait for the identifiers to be replicated from the server
|
-- wait for the identifiers to be replicated from the server
|
||||||
Replication.wait_for_ready = function()
|
Replication.wait_for_ready = function()
|
||||||
if is_ready then return end
|
if is_ready then return end
|
||||||
|
|
||||||
local thread = coroutine.running()
|
local thread = coroutine.running()
|
||||||
table.insert(ready_yields, thread)
|
table.insert(ready_yields, thread)
|
||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,17 @@
|
||||||
--@EternityDev
|
--@EternityDev
|
||||||
local Server = {}
|
local Server = {}
|
||||||
|
|
||||||
local Players = game:GetService("Players")
|
|
||||||
local RunService = game:GetService("RunService")
|
|
||||||
local Thread = require("./Util/Thread")
|
local Thread = require("./Util/Thread")
|
||||||
local Buffer = require("./Util/Buffer")
|
local Buffer = require("./Util/Buffer")
|
||||||
local Identifier = require("./Util/Identifier")
|
local Identifier = require("./Util/Identifier")
|
||||||
local Replication = require("./Replication")
|
local Replication = require("./Replication")
|
||||||
local Event: RemoteEvent = script.Parent:WaitForChild("Event")
|
local Xor = require("./Util/Xor")
|
||||||
local _repl: RemoteEvent = script.Parent:WaitForChild("_repl")
|
|
||||||
local UnreliableEvent: UnreliableRemoteEvent = script.Parent:WaitForChild("UnreliableEvent")
|
local Players = game:GetService("Players")
|
||||||
|
local RunService = game:GetService("RunService")
|
||||||
|
local Event: RemoteEvent = script.Parent:WaitForChild("Event") :: RemoteEvent
|
||||||
|
local _repl: RemoteEvent = script.Parent:WaitForChild("_repl") :: RemoteEvent
|
||||||
|
local UnreliableEvent: UnreliableRemoteEvent = script.Parent:WaitForChild("UnreliableEvent") :: UnreliableRemoteEvent
|
||||||
local deltaT: number, cycle: number = 0, 1 / 61
|
local deltaT: number, cycle: number = 0, 1 / 61
|
||||||
local writer: Buffer.Writer = Buffer.createWriter()
|
local writer: Buffer.Writer = Buffer.createWriter()
|
||||||
|
|
||||||
|
|
@ -180,7 +182,7 @@ Server.Invoke = function(remoteName: string, player: Player, timeout: number?, .
|
||||||
end
|
end
|
||||||
table.insert(queueEvent[player], {
|
table.insert(queueEvent[player], {
|
||||||
0,
|
0,
|
||||||
{ Identifier.get_id(remoteName), reqId :: any, { ... } :: any } :: any,
|
{ reqId :: any, { ... } :: any } :: any,
|
||||||
})
|
})
|
||||||
return coroutine.yield()
|
return coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
@ -198,14 +200,15 @@ if RunService:IsServer() then
|
||||||
player_bytes[player] = bytes
|
player_bytes[player] = bytes
|
||||||
end
|
end
|
||||||
|
|
||||||
local contents = Buffer.readEvents(b, ref, eventSchemas)
|
local decoded = handleInvokes and Xor.decodeServer(player, b) or b
|
||||||
|
local contents = Buffer.readEvents(decoded, ref, eventSchemas)
|
||||||
for _, content in contents do
|
for _, content in contents do
|
||||||
local remote = content[1]
|
local remote = content[1]
|
||||||
local content = content[2]
|
local d = content[2]
|
||||||
if handleInvokes then
|
if handleInvokes then
|
||||||
if remote == 1 then
|
if remote == 1 then
|
||||||
local id = content[1]
|
local id = d[1]
|
||||||
local results = content[2]
|
local results = d[2]
|
||||||
local pending = pendingInvokes[id]
|
local pending = pendingInvokes[id]
|
||||||
if pending then
|
if pending then
|
||||||
task.spawn(pending :: any, table.unpack(results))
|
task.spawn(pending :: any, table.unpack(results))
|
||||||
|
|
@ -214,12 +217,12 @@ if RunService:IsServer() then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
if remote == 0 then
|
if remote == 0 then
|
||||||
if #eventListeners == 0 then
|
if not next(eventListeners) then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
local remoteName = content[1]
|
local remoteName = d[1]
|
||||||
local id = content[2]
|
local id = d[2]
|
||||||
local args = content[3]
|
local args = d[3]
|
||||||
local connections = eventListeners[remoteName]
|
local connections = eventListeners[remoteName]
|
||||||
if connections and #connections > 0 then
|
if connections and #connections > 0 then
|
||||||
Thread(function()
|
Thread(function()
|
||||||
|
|
@ -239,7 +242,7 @@ if RunService:IsServer() then
|
||||||
local connections = eventListeners[remote]
|
local connections = eventListeners[remote]
|
||||||
if connections then
|
if connections then
|
||||||
for _, connection in connections do
|
for _, connection in connections do
|
||||||
Thread(connection.c, player, table.unpack(content))
|
Thread(connection.c :: any, player, table.unpack(d))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -268,11 +271,12 @@ if RunService:IsServer() then
|
||||||
Buffer.writeEvents(writer, content, eventSchemas)
|
Buffer.writeEvents(writer, content, eventSchemas)
|
||||||
do
|
do
|
||||||
local buf, ref = Buffer.buildWithRefs(writer)
|
local buf, ref = Buffer.buildWithRefs(writer)
|
||||||
|
local encoded = Xor.encodeServer(player, buf)
|
||||||
Buffer.reset(writer)
|
Buffer.reset(writer)
|
||||||
if not ref or #ref == 0 then
|
if not ref or #ref == 0 then
|
||||||
Event:FireClient(player, buf)
|
Event:FireClient(player, encoded)
|
||||||
else
|
else
|
||||||
Event:FireClient(player, buf, ref)
|
Event:FireClient(player, encoded, ref)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
player_bytes[player] = 0
|
player_bytes[player] = 0
|
||||||
|
|
@ -324,6 +328,7 @@ if RunService:IsServer() then
|
||||||
table.clear(queueUnreliableEvent[player])
|
table.clear(queueUnreliableEvent[player])
|
||||||
queueUnreliableEvent[player] = nil
|
queueUnreliableEvent[player] = nil
|
||||||
end
|
end
|
||||||
|
Xor.remove(player)
|
||||||
end)
|
end)
|
||||||
for _, player: Player in ipairs(Players:GetPlayers()) do
|
for _, player: Player in ipairs(Players:GetPlayers()) do
|
||||||
onAdded(player)
|
onAdded(player)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,11 @@ local T_BUFFER = 0xDC
|
||||||
local T_BOOL_ARR = 0xDD
|
local T_BOOL_ARR = 0xDD
|
||||||
|
|
||||||
local T_VEC3 = 0xE0
|
local T_VEC3 = 0xE0
|
||||||
|
local T_VEC3F32 = 0xE1
|
||||||
|
local T_VEC3I16 = 0xF1
|
||||||
local T_VEC2 = 0xE2
|
local T_VEC2 = 0xE2
|
||||||
|
local T_VEC2F32 = 0xE3
|
||||||
|
local T_VEC2I16 = 0xF4
|
||||||
local T_CFRAME = 0xE4
|
local T_CFRAME = 0xE4
|
||||||
local T_COLOR3 = 0xE6
|
local T_COLOR3 = 0xE6
|
||||||
local T_COLOR3_F = 0xE7
|
local T_COLOR3_F = 0xE7
|
||||||
|
|
@ -65,8 +69,6 @@ local T_NUMBERRANGE = 0xEF
|
||||||
local T_RAY = 0xF0
|
local T_RAY = 0xF0
|
||||||
local T_COLSEQ = 0xF2
|
local T_COLSEQ = 0xF2
|
||||||
local T_NUMSEQ = 0xF3
|
local T_NUMSEQ = 0xF3
|
||||||
local T_VEC3I16 = 0xF1
|
|
||||||
local T_VEC2I16 = 0xF4
|
|
||||||
local T_TWEENINFO = 0xF5
|
local T_TWEENINFO = 0xF5
|
||||||
local T_PHYSPROP = 0xF6
|
local T_PHYSPROP = 0xF6
|
||||||
local T_FONT = 0xF7
|
local T_FONT = 0xF7
|
||||||
|
|
@ -732,6 +734,14 @@ local function packVector3(w: Writer, v: Vector3)
|
||||||
rawF16(w, v.Z)
|
rawF16(w, v.Z)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function packVector3F32(w: Writer, v: Vector3)
|
||||||
|
ensureSpace(w, 13)
|
||||||
|
rawU8(w, T_VEC3F32)
|
||||||
|
rawF32(w, v.X)
|
||||||
|
rawF32(w, v.Y)
|
||||||
|
rawF32(w, v.Z)
|
||||||
|
end
|
||||||
|
|
||||||
local function packVector2(w: Writer, v: Vector2)
|
local function packVector2(w: Writer, v: Vector2)
|
||||||
ensureSpace(w, 5)
|
ensureSpace(w, 5)
|
||||||
rawU8(w, T_VEC2)
|
rawU8(w, T_VEC2)
|
||||||
|
|
@ -739,6 +749,13 @@ local function packVector2(w: Writer, v: Vector2)
|
||||||
rawF16(w, v.Y)
|
rawF16(w, v.Y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function packVector2F32(w: Writer, v: Vector2)
|
||||||
|
ensureSpace(w, 9)
|
||||||
|
rawU8(w, T_VEC2F32)
|
||||||
|
rawF32(w, v.X)
|
||||||
|
rawF32(w, v.Y)
|
||||||
|
end
|
||||||
|
|
||||||
local function packCFrame(w: Writer, cf: CFrame)
|
local function packCFrame(w: Writer, cf: CFrame)
|
||||||
local pos = cf.Position
|
local pos = cf.Position
|
||||||
local qi, q0, q1, q2 = compressCFrameRotation(cf)
|
local qi, q0, q1, q2 = compressCFrameRotation(cf)
|
||||||
|
|
@ -796,10 +813,33 @@ PACK_DISPATCH["Vector3"] = function(w: Writer, v: any)
|
||||||
packVector3(w, v)
|
packVector3(w, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
PACK_DISPATCH["Vector3F32"] = function(w: Writer, v: any)
|
||||||
|
packVector3F32(w, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
PACK_DISPATCH["Vector3int16"] = function(w: Writer, v: any)
|
||||||
|
ensureSpace(w, 7)
|
||||||
|
rawU8(w, T_VEC3I16)
|
||||||
|
rawI16(w, v.X)
|
||||||
|
rawI16(w, v.Y)
|
||||||
|
rawI16(w, v.Z)
|
||||||
|
end
|
||||||
|
|
||||||
PACK_DISPATCH["Vector2"] = function(w: Writer, v: any)
|
PACK_DISPATCH["Vector2"] = function(w: Writer, v: any)
|
||||||
packVector2(w, v)
|
packVector2(w, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
PACK_DISPATCH["Vector2F32"] = function(w: Writer, v: any)
|
||||||
|
packVector2F32(w, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
PACK_DISPATCH["Vector2int16"] = function(w: Writer, v: any)
|
||||||
|
ensureSpace(w, 5)
|
||||||
|
rawU8(w, T_VEC2I16)
|
||||||
|
rawI16(w, v.X)
|
||||||
|
rawI16(w, v.Y)
|
||||||
|
end
|
||||||
|
|
||||||
PACK_DISPATCH["CFrame"] = function(w: Writer, v: any)
|
PACK_DISPATCH["CFrame"] = function(w: Writer, v: any)
|
||||||
packCFrame(w, v)
|
packCFrame(w, v)
|
||||||
end
|
end
|
||||||
|
|
@ -924,21 +964,6 @@ PACK_DISPATCH["buffer"] = function(w: Writer, v: any)
|
||||||
w.cursor += len
|
w.cursor += len
|
||||||
end
|
end
|
||||||
|
|
||||||
PACK_DISPATCH["Vector3int16"] = function(w: Writer, v: any)
|
|
||||||
ensureSpace(w, 7)
|
|
||||||
rawU8(w, T_VEC3I16)
|
|
||||||
rawI16(w, v.X)
|
|
||||||
rawI16(w, v.Y)
|
|
||||||
rawI16(w, v.Z)
|
|
||||||
end
|
|
||||||
|
|
||||||
PACK_DISPATCH["Vector2int16"] = function(w: Writer, v: any)
|
|
||||||
ensureSpace(w, 5)
|
|
||||||
rawU8(w, T_VEC2I16)
|
|
||||||
rawI16(w, v.X)
|
|
||||||
rawI16(w, v.Y)
|
|
||||||
end
|
|
||||||
|
|
||||||
PACK_DISPATCH["TweenInfo"] = function(w: Writer, v: any)
|
PACK_DISPATCH["TweenInfo"] = function(w: Writer, v: any)
|
||||||
ensureSpace(w, 16) -- tag(1) + f32(4) + u8(1) + u8(1) + i32(4) + u8(1) + f32(4)
|
ensureSpace(w, 16) -- tag(1) + f32(4) + u8(1) + u8(1) + i32(4) + u8(1) + f32(4)
|
||||||
rawU8(w, T_TWEENINFO)
|
rawU8(w, T_TWEENINFO)
|
||||||
|
|
@ -1066,15 +1091,6 @@ UNPACK[T_F64 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number):
|
||||||
return buffer.readf64(buf, pos), pos + 8
|
return buffer.readf64(buf, pos), pos + 8
|
||||||
end
|
end
|
||||||
|
|
||||||
UNPACK[T_VEC3I16 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
|
||||||
return Vector3int16.new(buffer.readi16(buf, pos), buffer.readi16(buf, pos + 2), buffer.readi16(buf, pos + 4)),
|
|
||||||
pos + 6
|
|
||||||
end
|
|
||||||
|
|
||||||
UNPACK[T_VEC2I16 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
|
||||||
return Vector2int16.new(buffer.readi16(buf, pos), buffer.readi16(buf, pos + 2)), pos + 4
|
|
||||||
end
|
|
||||||
|
|
||||||
UNPACK[T_TWEENINFO + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
UNPACK[T_TWEENINFO + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
return TweenInfo.new(
|
return TweenInfo.new(
|
||||||
buffer.readf32(buf, pos),
|
buffer.readf32(buf, pos),
|
||||||
|
|
@ -1288,6 +1304,20 @@ UNPACK[T_VEC3 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number):
|
||||||
return Vector3.new(x, y, z), pos + 6
|
return Vector3.new(x, y, z), pos + 6
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Vector3 float32
|
||||||
|
UNPACK[T_VEC3F32 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
|
local x = buffer.readf32(buf, pos)
|
||||||
|
local y = buffer.readf32(buf, pos + 4)
|
||||||
|
local z = buffer.readf32(buf, pos + 8)
|
||||||
|
return Vector3.new(x, y, z), pos + 12
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Vector3int16
|
||||||
|
UNPACK[T_VEC3I16 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
|
return Vector3int16.new(buffer.readi16(buf, pos), buffer.readi16(buf, pos + 2), buffer.readi16(buf, pos + 4)),
|
||||||
|
pos + 6
|
||||||
|
end
|
||||||
|
|
||||||
-- Vector2
|
-- Vector2
|
||||||
UNPACK[T_VEC2 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
UNPACK[T_VEC2 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
local x = readF16(buf, pos)
|
local x = readF16(buf, pos)
|
||||||
|
|
@ -1295,6 +1325,18 @@ UNPACK[T_VEC2 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number):
|
||||||
return Vector2.new(x, y), pos + 4
|
return Vector2.new(x, y), pos + 4
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Vector2 float32
|
||||||
|
UNPACK[T_VEC2F32 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
|
local x = buffer.readf32(buf, pos)
|
||||||
|
local y = buffer.readf32(buf, pos + 4)
|
||||||
|
return Vector2.new(x, y), pos + 8
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Vector2int16
|
||||||
|
UNPACK[T_VEC2I16 + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
|
return Vector2int16.new(buffer.readi16(buf, pos), buffer.readi16(buf, pos + 2)), pos + 4
|
||||||
|
end
|
||||||
|
|
||||||
-- CFrame
|
-- CFrame
|
||||||
UNPACK[T_CFRAME + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
UNPACK[T_CFRAME + 1] = function(buf: buffer, pos: number, _: { any }?, _: number): (any, number)
|
||||||
local px = buffer.readf32(buf, pos)
|
local px = buffer.readf32(buf, pos)
|
||||||
|
|
@ -1469,7 +1511,11 @@ Schema.f32 = { type = "f32" }
|
||||||
Schema.f64 = { type = "f64" }
|
Schema.f64 = { type = "f64" }
|
||||||
Schema.boolean = { type = "boolean" }
|
Schema.boolean = { type = "boolean" }
|
||||||
Schema.vector3 = { type = "vector3" }
|
Schema.vector3 = { type = "vector3" }
|
||||||
|
Schema.vector3f32 = { type = "vector3f32" }
|
||||||
|
Schema.vector3int16 = { type = "vector3int16" }
|
||||||
Schema.vector2 = { type = "vector2" }
|
Schema.vector2 = { type = "vector2" }
|
||||||
|
Schema.vector2f32 = { type = "vector2f32" }
|
||||||
|
Schema.vector2int16 = { type = "vector2int16" }
|
||||||
Schema.cframe = { type = "cframe" }
|
Schema.cframe = { type = "cframe" }
|
||||||
Schema.color3 = { type = "color3" }
|
Schema.color3 = { type = "color3" }
|
||||||
Schema.color3f16 = { type = "color3f16" }
|
Schema.color3f16 = { type = "color3f16" }
|
||||||
|
|
@ -1484,8 +1530,6 @@ Schema.colorsequence = { type = "colorsequence" }
|
||||||
Schema.numbersequence = { type = "numbersequence" }
|
Schema.numbersequence = { type = "numbersequence" }
|
||||||
Schema.brickcolor = { type = "brickcolor" }
|
Schema.brickcolor = { type = "brickcolor" }
|
||||||
Schema.buffer = { type = "buffer" }
|
Schema.buffer = { type = "buffer" }
|
||||||
Schema.vector3int16 = { type = "vector3int16" }
|
|
||||||
Schema.vector2int16 = { type = "vector2int16" }
|
|
||||||
Schema.tweeninfo = { type = "tweeninfo" }
|
Schema.tweeninfo = { type = "tweeninfo" }
|
||||||
Schema.physicalproperties = { type = "physicalproperties" }
|
Schema.physicalproperties = { type = "physicalproperties" }
|
||||||
Schema.font = { type = "font" }
|
Schema.font = { type = "font" }
|
||||||
|
|
@ -1544,7 +1588,11 @@ local SCHEMA_FIXED_SIZES: { [string]: number } = {
|
||||||
f64 = 8,
|
f64 = 8,
|
||||||
boolean = 1,
|
boolean = 1,
|
||||||
vector3 = 6,
|
vector3 = 6,
|
||||||
|
vector3f32 = 12,
|
||||||
|
vector3int16 = 6,
|
||||||
vector2 = 4,
|
vector2 = 4,
|
||||||
|
vector2f32 = 8,
|
||||||
|
vector2int16 = 4,
|
||||||
cframe = 19,
|
cframe = 19,
|
||||||
color3 = 3,
|
color3 = 3,
|
||||||
color3f16 = 6,
|
color3f16 = 6,
|
||||||
|
|
@ -1554,8 +1602,6 @@ local SCHEMA_FIXED_SIZES: { [string]: number } = {
|
||||||
numberrange = 8,
|
numberrange = 8,
|
||||||
ray = 24,
|
ray = 24,
|
||||||
brickcolor = 2,
|
brickcolor = 2,
|
||||||
vector3int16 = 6,
|
|
||||||
vector2int16 = 4,
|
|
||||||
tweeninfo = 15,
|
tweeninfo = 15,
|
||||||
physicalproperties = 20,
|
physicalproperties = 20,
|
||||||
datetime = 8,
|
datetime = 8,
|
||||||
|
|
@ -1637,7 +1683,6 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
rawString(w, v, len)
|
rawString(w, v, len)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if schema_type == "vector3" then
|
if schema_type == "vector3" then
|
||||||
return function(w: Writer, v: any)
|
return function(w: Writer, v: any)
|
||||||
ensureSpace(w, 6)
|
ensureSpace(w, 6)
|
||||||
|
|
@ -1646,6 +1691,14 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
rawF16(w, v.Z)
|
rawF16(w, v.Z)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if schema_type == "vector3f32" then
|
||||||
|
return function(w: Writer, v: any)
|
||||||
|
ensureSpace(w, 12)
|
||||||
|
rawF32(w, v.X)
|
||||||
|
rawF32(w, v.Y)
|
||||||
|
rawF32(w, v.Z)
|
||||||
|
end
|
||||||
|
end
|
||||||
if schema_type == "vector2" then
|
if schema_type == "vector2" then
|
||||||
return function(w: Writer, v: any)
|
return function(w: Writer, v: any)
|
||||||
ensureSpace(w, 4)
|
ensureSpace(w, 4)
|
||||||
|
|
@ -1653,6 +1706,13 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
rawF16(w, v.Y)
|
rawF16(w, v.Y)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if schema_type == "vector2f32" then
|
||||||
|
return function(w: Writer, v: any)
|
||||||
|
ensureSpace(w, 8)
|
||||||
|
rawF32(w, v.X)
|
||||||
|
rawF32(w, v.Y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if schema_type == "cframe" then
|
if schema_type == "cframe" then
|
||||||
return function(w: Writer, v: any)
|
return function(w: Writer, v: any)
|
||||||
|
|
@ -2084,6 +2144,14 @@ local function compileReader(s: SchemaType): (buffer, number, { any }?) -> (any,
|
||||||
return Vector3.new(x, y, z), c + 6
|
return Vector3.new(x, y, z), c + 6
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if schema_type == "vector3f32" then
|
||||||
|
return function(b: buffer, c: number)
|
||||||
|
local x = buffer.readf32(b, c)
|
||||||
|
local y = buffer.readf32(b, c + 4)
|
||||||
|
local z = buffer.readf32(b, c + 8)
|
||||||
|
return Vector3.new(x, y, z), c + 12
|
||||||
|
end
|
||||||
|
end
|
||||||
if schema_type == "vector2" then
|
if schema_type == "vector2" then
|
||||||
return function(b: buffer, c: number)
|
return function(b: buffer, c: number)
|
||||||
local x = readF16(b, c)
|
local x = readF16(b, c)
|
||||||
|
|
@ -2091,6 +2159,13 @@ local function compileReader(s: SchemaType): (buffer, number, { any }?) -> (any,
|
||||||
return Vector2.new(x, y), c + 4
|
return Vector2.new(x, y), c + 4
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if schema_type == "vector2f32" then
|
||||||
|
return function(b: buffer, c: number)
|
||||||
|
local x = buffer.readf32(b, c)
|
||||||
|
local y = buffer.readf32(b, c + 4)
|
||||||
|
return Vector2.new(x, y), c + 8
|
||||||
|
end
|
||||||
|
end
|
||||||
if schema_type == "color3" then
|
if schema_type == "color3" then
|
||||||
return function(b: buffer, c: number)
|
return function(b: buffer, c: number)
|
||||||
local r = buffer.readu8(b, c)
|
local r = buffer.readu8(b, c)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
--!strict
|
--!strict
|
||||||
--@EternityDev
|
--@EternityDev
|
||||||
local BITS: number = 8
|
const BITS: number = 8
|
||||||
local MAX_VALUE: number = bit32.lshift(1, BITS) - 1
|
const MAX_VALUE: number = bit32.lshift(1, BITS) - 1
|
||||||
local hook_fn: (string, number) -> ()
|
local hook_fn: (string, number) -> ()
|
||||||
|
|
||||||
if not shared.__warp_identifier_registry then
|
if not shared.__warp_identifier_registry then
|
||||||
|
|
|
||||||
120
src/Util/Xor.luau
Normal file
120
src/Util/Xor.luau
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
--!strict
|
||||||
|
--!native
|
||||||
|
--!optimize 2
|
||||||
|
local Xor = {}
|
||||||
|
|
||||||
|
type XorEntry = { buf: buffer, len: number }
|
||||||
|
|
||||||
|
local serverPrev: { [Player]: XorEntry } = {}
|
||||||
|
local clientPrev: { [Player]: XorEntry } = {}
|
||||||
|
|
||||||
|
local clientOutPrev: XorEntry? = nil
|
||||||
|
local clientInPrev: XorEntry? = nil
|
||||||
|
const MAX_BUFFER_SIZE: number = 1024
|
||||||
|
|
||||||
|
local function xorApply(
|
||||||
|
current: buffer, curLen: number,
|
||||||
|
prev: buffer, prevLen: number
|
||||||
|
): buffer
|
||||||
|
local out = buffer.create(curLen)
|
||||||
|
local common = if curLen < prevLen then curLen else prevLen
|
||||||
|
|
||||||
|
local wordEnd = (common // 4) * 4
|
||||||
|
for off = 0, wordEnd - 4, 4 do
|
||||||
|
buffer.writeu32(
|
||||||
|
out, off,
|
||||||
|
bit32.bxor(buffer.readu32(current, off), buffer.readu32(prev, off))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
for i = wordEnd, common - 1 do
|
||||||
|
buffer.writeu8(
|
||||||
|
out, i,
|
||||||
|
bit32.bxor(buffer.readu8(current, i), buffer.readu8(prev, i))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
if curLen > common then
|
||||||
|
buffer.copy(out, common, current, common, curLen - common)
|
||||||
|
end
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
local function storeEntry(entry: XorEntry?, src: buffer, len: number): XorEntry
|
||||||
|
local e: XorEntry = entry or { buf = buffer.create(math.max(len, 64)), len = 0 }
|
||||||
|
local cap = buffer.len(e.buf)
|
||||||
|
|
||||||
|
if cap < len then
|
||||||
|
e.buf = buffer.create(math.min(len * 2, MAX_BUFFER_SIZE + len))
|
||||||
|
elseif cap > len * 4 and cap > 128 then
|
||||||
|
e.buf = buffer.create(math.max(len, 64))
|
||||||
|
end
|
||||||
|
|
||||||
|
buffer.copy(e.buf, 0, src, 0, len)
|
||||||
|
e.len = len
|
||||||
|
return e
|
||||||
|
end
|
||||||
|
|
||||||
|
function Xor.remove(player: Player)
|
||||||
|
serverPrev[player] = nil
|
||||||
|
clientPrev[player] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Xor.encodeServer(player: Player, buf: buffer): buffer
|
||||||
|
local len = buffer.len(buf)
|
||||||
|
local entry = serverPrev[player]
|
||||||
|
|
||||||
|
if not entry then
|
||||||
|
serverPrev[player] = storeEntry(nil, buf, len)
|
||||||
|
return buf
|
||||||
|
end
|
||||||
|
|
||||||
|
local encoded = xorApply(buf, len, entry.buf, entry.len)
|
||||||
|
serverPrev[player] = storeEntry(entry, buf, len)
|
||||||
|
return encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
function Xor.decodeClient(buf: buffer): buffer
|
||||||
|
local len = buffer.len(buf)
|
||||||
|
local prev = clientInPrev
|
||||||
|
|
||||||
|
if not prev then
|
||||||
|
clientInPrev = storeEntry(nil, buf, len)
|
||||||
|
return buf
|
||||||
|
end
|
||||||
|
|
||||||
|
local recovered = xorApply(buf, len, prev.buf, prev.len)
|
||||||
|
clientInPrev = storeEntry(prev, recovered, len)
|
||||||
|
return recovered
|
||||||
|
end
|
||||||
|
|
||||||
|
function Xor.encodeClient(buf: buffer): buffer
|
||||||
|
local len = buffer.len(buf)
|
||||||
|
local prev = clientOutPrev
|
||||||
|
|
||||||
|
if not prev then
|
||||||
|
clientOutPrev = storeEntry(nil, buf, len)
|
||||||
|
return buf
|
||||||
|
end
|
||||||
|
|
||||||
|
local encoded = xorApply(buf, len, prev.buf, prev.len)
|
||||||
|
clientOutPrev = storeEntry(prev, buf, len)
|
||||||
|
return encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
function Xor.decodeServer(player: Player, buf: buffer): buffer
|
||||||
|
local len = buffer.len(buf)
|
||||||
|
local entry = clientPrev[player]
|
||||||
|
|
||||||
|
if not entry then
|
||||||
|
clientPrev[player] = storeEntry(nil, buf, len)
|
||||||
|
return buf
|
||||||
|
end
|
||||||
|
|
||||||
|
local recovered = xorApply(buf, len, entry.buf, entry.len)
|
||||||
|
clientPrev[player] = storeEntry(entry, recovered, len)
|
||||||
|
return recovered
|
||||||
|
end
|
||||||
|
|
||||||
|
Xor._apply = xorApply
|
||||||
|
|
||||||
|
return Xor
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "imezx/warp"
|
name = "imezx/warp"
|
||||||
version = "1.1.0-pre4"
|
version = "1.1.0-pre7"
|
||||||
registry = "https://github.com/UpliftGames/wally-index"
|
registry = "https://github.com/UpliftGames/wally-index"
|
||||||
realm = "shared"
|
realm = "shared"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue