I have been wondering if event:FireServer(1.123)
takes up less bandwidth than event:FireServer(1.123456)
, or are they both the exact same, as in they are both double precision floats, so they must take up the same exact bandwidth?
I don’t believe that just because the shortest precise decimal expansion of the double of the former has less digits than the letter, it’ll mean it’ll take up less bandwidth.
I believe they take up the same bandwidth so no, I don’t believe that it costs less to send 1.123
than 1.123456
via remote events.
Yeah that does seem like the most logical answer, but here is another one, is doing event:FireServer(1)
cheaper than event:FireServer(1.123)
, if no (which I think is the right answer as all numbers in lua are double precision), then is there a way to explicitely send integers to save bandwidth? Same way you have Vector3int16 which is composed of 16bit signed integers.
I doubt it is, they would need some sort of integer type indicator along with it. There is no integer type, and they don’t have to add a hidden one just for remote events.
A somewhat hacky way to do this is to use a Vector2int16, left shift one of the axes, and use bitwise OR. Before sending we would use bitwise AND and right shift it. The client would do this:
local function cast_to_vector2int16(n)
return Vector2int16.new(bit32.band(n, 0x11110000), bit32.band(n, 0x00001111))
end
event:FireServer(cast_to_vector2int16(1))
and the server would call this when recieving:
local function cast_back_to_number(v2i16)
return bit32.bor(bit32.lshift(v2i16.X, 16), v2i16.Y)
end
That’s actually pretty neat, as long as it saves bandwidth I dont see anything wrong with it.
Would there be a similar way to send single (binary32) or half (binary16) floats to save bandwidth if i need the decimal point?
I would put a decimal point after the last (or first, in bit positions) 3 bits when doing the same thing with a 32 bit number, so it would be a 29 bit number + x/8
. If you won’t mess with large numbers I could say this is OK but otherwise you could actually make it, but I don’t think either of these are worth it. You would be saving only 4 bytes.
You could always use string.pack
with f
for single then unpack it as two
short
(int16
) value hh
.
Vector2int16.new(string.unpack("hh", string.pack("f", value)))
(or simply send it as strings but I’m not sure how much bandwidth would this take)
Not sure about binary16.
I am not sure what that does, it’s not really returning the number i inputed? I may be using it wrong but it gave me the idea of using Vector2int16.new()
and use X
as the integer and Y
as the decimal portion of the float. So something like this:
local function numberToVec2int(number: number)
return Vector2int16.new(math.clamp(math.floor(number), -32768, 32767), math.round(math.fmod(number, 1) * (10 ^ 4)))
end
local function vec2intToNumber(vec2: Vector2int16)
return tonumber(vec2.X .. "." .. vec2.Y)
end
The problem with that is your number will cant be larger than 32767
or smaller than -32768
, but I dont think my map will exceed 32k studs either directions.
Correct me if I am wrong, but this should save 32bits?
Yes, a double is usually 64 bits. I can’t really understand what you’ve done there, To move the decimal point, you could have first multiplied the number by 8 on the client, and then divided the number by 8 on the server.
No. All lua numbers are sent as signed float64s with a one-byte overhead for their type, meaning they take 9 bytes in total to pass through a remote.
An int16, in comparison, is only 2 bytes, 3 including a byte overhead.
I made a plugin specifically to observe this kind of behavior, which you can use:
What I have done is rather simple:
local function numberToVec2int(number: number): Vector2int16
return Vector2int16.new(math.clamp(math.floor(number), -32768, 32767), math.round(math.fmod(number, 1) * (10 ^ 4)))
end
local function vec2intToNumber(vec2: Vector2int16): number
return tonumber(vec2.X .. "." .. vec2.Y)
end
-- On server
event:FireAllClients(numberToVec2int(12345.123456789)) -- This sends 32bits worth of data
-- On client
event.OnClientEvent:Connect(function(compressedNumber)
local num: number = vec2intToNumber(compressedNumber)
print(num) -- 12345.1235
end)
So instead of sending 64bits worth of data, i take the number and “compress” it using vector2int16 and I send it to the client which results in me sending only 32bits, then client receives it and switches it back to a number.