· 4 years ago · Aug 25, 2021, 08:18 PM
1local API = {}
2
3---@type Base64
4local Base64 = require(script:GetCustomProperty("Base64"))
5
6local TYPE_TOKENS = {
7 NIL = 1,
8 POS_INT6 = 2,
9 POS_INT12 = 3,
10 POS_UINT18 = 4,
11 POS_UINT24 = 5,
12 NEG_INT6 = 6,
13 NEG_INT12 = 7,
14 NEG_INT18 = 8,
15 NEG_INT24 = 9,
16 BOOLEAN = 10,
17 CHAR = 11,
18 STRING_6 = 12,
19 STRING_12 = 13,
20 STRING_18 = 14,
21 TABLE_6 = 15,
22 TABLE_12 = 16,
23 TABLE_18 = 17,
24 ARRAY_6 = 18,
25 ARRAY_12 = 19,
26 ARRAY_18 = 20,
27 NORMALIZED_FLOAT = 21,
28 FLOAT = 22,
29}
30
31---comment
32---@param t table
33
34function TableIsArray(t)
35 assert(type(t) == "table")
36 return TableKeyCount(t) == #t
37end
38
39function TableKeyCount(t)
40 local count = 0
41 for k, v in pairs(t) do
42 count = count+1
43 end
44 return count
45end
46
47function IsWholeNumber(n)
48 assert(type(n) == "number")
49 return n == CoreMath.Round(n)
50end
51
52function IsNormalizedNumber(n)
53 assert(type(n) == "number")
54 return n >= 0 and n <= 1
55end
56
57function NormalizedFloatToUInt6(value)
58 assert(type(value) == "number")
59 assert(value >= 0 and value <= 1)
60 return CoreMath.Clamp(CoreMath.Round(value*63), 0, 63)
61end
62
63function UInt6ToNormalizedFloat(integer)
64 return CoreMath.Clamp(integer / 63)
65end
66
67
68function WriteValue(value, buffer)
69 local valueType = type(value)
70 if valueType == "nil" then
71 buffer.AppendTypeToken(TYPE_TOKENS.NIL)
72 elseif valueType == "boolean" then
73 buffer.AppendTypeToken(TYPE_TOKENS.BOOLEAN)
74 buffer.AppendString(Base64.EncodeBoolean(value))
75 elseif valueType == "number" then
76 if IsWholeNumber(value) then
77 if value >= 0 then
78 if value <= Base64.MAX_6 then
79 buffer.AppendTypeToken(TYPE_TOKENS.POS_INT6)
80 buffer.AppendString(Base64.Encode6(value))
81 elseif value <= Base64.MAX_12 then
82 buffer.AppendTypeToken(TYPE_TOKENS.POS_INT12)
83 buffer.AppendString(Base64.Encode12(value))
84 elseif value <= Base64.MAX_18 then
85 buffer.AppendTypeToken(TYPE_TOKENS.POS_INT18)
86 buffer.AppendString(Base64.Encode18(value))
87 elseif value <= Base64.MAX_24 then
88 buffer.AppendTypeToken(TYPE_TOKENS.POS_INT24)
89 buffer.AppendString(Base64.Encode24(value))
90 else
91 error("Whole number is too large to encode")
92 end
93 else
94 value = -value -- make negative positive
95 if value <= Base64.MAX_6 then
96 buffer.AppendTypeToken(TYPE_TOKENS.NEG_INT6)
97 buffer.AppendString(Base64.Encode6(value))
98 elseif value <= Base64.MAX_12 then
99 buffer.AppendTypeToken(TYPE_TOKENS.NEG_INT12)
100 buffer.AppendString(Base64.Encode12(value))
101 elseif value <= Base64.MAX_18 then
102 buffer.AppendTypeToken(TYPE_TOKENS.NEG_INT18)
103 buffer.AppendString(Base64.Encode18(value))
104 elseif value <= Base64.MAX_24 then
105 buffer.AppendTypeToken(TYPE_TOKENS.NEG_INT24)
106 buffer.AppendString(Base64.Encode24(value))
107 else
108 error("Whole number is too large to encode (negative)")
109 end
110 end
111 else
112 if IsNormalizedNumber(value) then
113 buffer.AppendTypeToken(TYPE_TOKENS.NORMALIZED_FLOAT)
114 local i = NormalizedFloatToUInt6(value)
115 buffer.AppendString(Base64.Encode6(i))
116 else
117 error("Currently dont support floats outside the range of 0-1")
118 end
119 end
120 elseif valueType == "string" then
121 local count = #value
122 if count <= Base64.MAX_6 then
123 buffer.AppendTypeToken(TYPE_TOKENS.STRING_6)
124 buffer.AppendString(Base64.Encode6(count))
125 elseif count <= Base64.MAX_12 then
126 buffer.AppendTypeToken(TYPE_TOKENS.STRING_12)
127 buffer.AppendString(Base64.Encode12(count))
128 elseif count <= Base64.MAX_18 then
129 buffer.AppendTypeToken(TYPE_TOKENS.STRING_18)
130 buffer.AppendString(Base64.Encode12(count))
131 else
132 error("String has too many characters in it to encode")
133 end
134 buffer.AppendString(value)
135 elseif valueType == "table" then
136 if TableIsArray(value) then
137 local count = #value
138 if count <= Base64.MAX_6 then
139 buffer.AppendTypeToken(TYPE_TOKENS.ARRAY_6)
140 buffer.AppendString(Base64.Encode6(count))
141 elseif count <= Base64.MAX_12 then
142 buffer.AppendTypeToken(TYPE_TOKENS.ARRAY_12)
143 buffer.AppendString(Base64.Encode12(count))
144 elseif count <= Base64.MAX_18 then
145 buffer.AppendTypeToken(TYPE_TOKENS.ARRAY_18)
146 buffer.AppendString(Base64.Encode18(count))
147 else
148 error("There are too many items in the array")
149 end
150 for _, v in ipairs(value) do
151 WriteValue(v, buffer)
152 end
153 else
154 local count = TableKeyCount(value)
155 if count <= Base64.MAX_6 then
156 buffer.AppendTypeToken(TYPE_TOKENS.TABLE_6)
157 buffer.AppendString(Base64.Encode6(count))
158 elseif count <= Base64.MAX_12 then
159 buffer.AppendTypeToken(TYPE_TOKENS.TABLE_12)
160 buffer.AppendString(Base64.Encode12(count))
161 elseif count <= Base64.MAX_18 then
162 buffer.AppendTypeToken(TYPE_TOKENS.TABLE_18)
163 buffer.AppendString(Base64.Encode18(count))
164 else
165 error("There are too many items in the array")
166 end
167 for k, v in pairs(value) do
168 WriteValue(k, buffer)
169 WriteValue(v, buffer)
170 end
171 end
172 elseif valueType == "userdata" then
173 -- Built in core types! Vector2, Vector3, Rotation, Quaternion, CoreObjectReference, etc
174 error ("userdata currently not supported")
175 else
176 error ("Unsupported type found")
177 end
178end
179
180function ReadTable(buffer, count)
181 local result = {}
182 for i=1, count do
183 local key = ReadValue(buffer)
184 local value = ReadValue(buffer)
185 result[key] = value
186 end
187 return result
188end
189
190function ReadArray(buffer, count)
191 local result = {}
192 for i=1, count do
193 local value = ReadValue(buffer)
194 result[i] = value
195 end
196 return result
197end
198
199local READ_TOKEN_METHODS = {
200 [TYPE_TOKENS.NIL] = function(buffer)
201 return
202 end,
203 [TYPE_TOKENS.POS_INT6] = function(buffer)
204 return Base64.Decode6(buffer.ReadString(1))
205 end,
206 [TYPE_TOKENS.POS_INT12] = function(buffer)
207 return Base64.Decode12(buffer.ReadString(2))
208 end,
209 [TYPE_TOKENS.POS_UINT18] = function(buffer)
210 return Base64.Decode18(buffer.ReadString(3))
211 end,
212 [TYPE_TOKENS.POS_UINT24] = function(buffer)
213 return Base64.Decode24(buffer.ReadString(4))
214 end,
215 [TYPE_TOKENS.NEG_INT6] = function(buffer)
216 return -Base64.Decode6(buffer.ReadString(1))
217 end,
218 [TYPE_TOKENS.NEG_INT12] = function(buffer)
219 return -Base64.Decode12(buffer.ReadString(2))
220 end,
221 [TYPE_TOKENS.NEG_INT18] = function(buffer)
222 return -Base64.Decode18(buffer.ReadString(3))
223 end,
224 [TYPE_TOKENS.NEG_INT24] = function(buffer)
225 return -Base64.Decode24(buffer.ReadString(4))
226 end,
227 [TYPE_TOKENS.BOOLEAN] = function(buffer)
228 return Base64.DecodeBoolean(buffer.ReadString(1))
229 end,
230 [TYPE_TOKENS.CHAR] = function(buffer)
231 return buffer.ReadString(1)
232 end,
233 [TYPE_TOKENS.STRING_6] = function(buffer)
234 local count = Base64.Decode6(buffer.ReadString(1))
235 return buffer.ReadString(count)
236 end,
237 [TYPE_TOKENS.STRING_12] = function(buffer)
238 local count = Base64.Decode12(buffer.ReadString(2))
239 return buffer.ReadString(count)
240 end,
241 [TYPE_TOKENS.STRING_18] = function(buffer)
242 local count = Base64.Decode18(buffer.ReadString(3))
243 return buffer.ReadString(count)
244 end,
245 [TYPE_TOKENS.TABLE_6] = function(buffer)
246 local count = Base64.Decode6(buffer.ReadString(1))
247 return ReadTable(buffer, count)
248 end,
249 [TYPE_TOKENS.TABLE_12] = function(buffer)
250 local count = Base64.Decode12(buffer.ReadString(2))
251 return ReadTable(buffer, count)
252 end,
253 [TYPE_TOKENS.TABLE_18] = function(buffer)
254 local count = Base64.Decode18(buffer.ReadString(3))
255 return ReadTable(buffer, count)
256 end,
257 [TYPE_TOKENS.ARRAY_6] = function(buffer)
258 local count = Base64.Decode6(buffer.ReadString(1))
259 return ReadArray(buffer, count)
260 end,
261 [TYPE_TOKENS.ARRAY_12] = function(buffer)
262 local count = Base64.Decode12(buffer.ReadString(2))
263 return ReadArray(buffer, count)
264 end,
265 [TYPE_TOKENS.ARRAY_18] = function(buffer)
266 local count = Base64.Decode18(buffer.ReadString(3))
267 return ReadArray(buffer, count)
268 end,
269 [TYPE_TOKENS.NORMALIZED_FLOAT] = function(buffer)
270 return UInt6ToNormalizedFloat( Base64.Decode6(buffer.ReadString(1)))
271 end,
272}
273
274
275function ReadValue(buffer)
276 local token = buffer.ReadTypeToken()
277 local method = READ_TOKEN_METHODS[token]
278 if method == nil then
279 error("Unable to find a method for the token " .. token)
280 end
281 return method(buffer)
282end
283
284function API.WriteString(...)
285 local buffer = {}
286 local stream = {}
287 local writeIndex = 1
288 function buffer.AppendTypeToken(token)
289 stream[writeIndex] = string.char(token)
290 writeIndex = writeIndex+1
291 end
292 function buffer.AppendString(s)
293 stream[writeIndex] = s
294 writeIndex = writeIndex+1
295 end
296 for _, param in ipairs({...}) do
297 WriteValue(param, buffer)
298 end
299 return table.concat(stream)
300end
301
302
303function API.ReadString(s)
304 local buffer = {}
305 local stream = s
306 local readIndex = 1
307 local length = #s
308 function buffer.ReadString(charCount)
309 assert(readIndex+charCount-1 <= length , "We have read past the end of the string")
310 local s = string.sub(stream, readIndex, readIndex+charCount-1)
311 readIndex = readIndex + charCount
312 return s
313 end
314 function buffer.ReadTypeToken()
315 local char = buffer.ReadString(1)
316 return string.byte(char)
317 end
318
319 local result = {}
320 while readIndex < length do
321 result[#result+1] = ReadValue(buffer)
322 end
323 return table.unpack(result)
324end
325
326function Tests()
327
328 local testString = API.WriteString(12,5, "hello", "world", 0.5)
329 print(testString)
330 local a, b, c, d, e, f = API.ReadString(testString)
331
332 --local testString = API.WriteString(12,5,{8}, "hello", "world", 0.5)
333 --local a, b, c, d, e, f = API.ReadString(testString)
334
335 local testTable = {
336 what = {
337 the = 50,
338 test = "string",
339 },
340 something = {
341 1,2,3,4,5
342 },
343 posX = 10,
344 posY = 20,
345 posZ = 0.5
346 }
347
348 local testString = API.WriteString(testTable)
349 print(testString)
350 --local t = API.ReadString(testString)
351 --print (t.what.the)
352
353 print ("Sending using cores method")
354 Events.BroadcastToServer("Testing the limjjjjjjjjits!!!!!!Tesjjjjjjjjjjjting thelimits!!!!!!", testTable)
355 print ("Sending as a token string")
356 Events.BroadcastToServer("Testing the limjjjjjjjjits!!!!!!Tesjjjjjjjjjjjting thelimits!!!!!!", testString)
357
358 Events.BroadcastToServer("Testing the limjjjjjjjjits!!!!!!Tesjjjjjjjjjjjting thelimits!!!!!!")
359 print ("fin!")
360
361end
362
363
364
365
366
367return API