@axpecter/lync 2.3.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +302 -299
- package/Types.luau +215 -0
- package/api/Define.luau +154 -0
- package/api/Lifecycle.luau +119 -0
- package/api/Packet.luau +108 -0
- package/api/Query.luau +149 -0
- package/api/Set.luau +189 -0
- package/channel/Blocks.luau +124 -0
- package/channel/Group.luau +118 -0
- package/channel/Link.luau +135 -0
- package/channel/Outbox.luau +261 -0
- package/channel/Recipients.luau +129 -0
- package/channel/Transport.luau +138 -0
- package/codec/Base.luau +236 -0
- package/codec/Composites.luau +128 -0
- package/codec/Datatypes.luau +162 -0
- package/codec/Legality.luau +61 -0
- package/codec/Scalars.luau +72 -0
- package/codec/Text.luau +89 -0
- package/codec/init.luau +39 -0
- package/index.d.ts +285 -0
- package/init.luau +91 -0
- package/kernel/Bits.luau +16 -0
- package/kernel/Catalog.luau +121 -0
- package/kernel/Heap.luau +80 -0
- package/kernel/Listeners.luau +95 -0
- package/kernel/Log.luau +197 -0
- package/kernel/Tally.luau +128 -0
- package/kernel/Threads.luau +44 -0
- package/kernel/Wide.luau +267 -0
- package/package.json +15 -32
- package/runtime/Boundary.luau +180 -0
- package/runtime/Dispatch.luau +91 -0
- package/runtime/Handles.luau +114 -0
- package/runtime/Handshake.luau +90 -0
- package/runtime/Pending.luau +196 -0
- package/runtime/Router.luau +379 -0
- package/runtime/Session.luau +731 -0
- package/shape/Compile.luau +340 -0
- package/shape/Folds.luau +332 -0
- package/shape/Frames.luau +170 -0
- package/shape/Grid.luau +169 -0
- package/shape/Ir.luau +540 -0
- package/shape/Joins.luau +125 -0
- package/shape/Legality.luau +273 -0
- package/shape/Lower.luau +419 -0
- package/shape/Order.luau +64 -0
- package/shape/Regions.luau +113 -0
- package/shape/Rotation.luau +472 -0
- package/shape/Serial.luau +258 -0
- package/shape/Words.luau +89 -0
- package/shape/emit/Block.luau +453 -0
- package/shape/emit/Column.luau +338 -0
- package/shape/emit/Leaf.luau +462 -0
- package/shape/emit/Word.luau +234 -0
- package/shape/emit/init.luau +222 -0
- package/shape/init.luau +78 -0
- package/state/Apply.luau +330 -0
- package/state/Audience.luau +126 -0
- package/state/Catchup.luau +218 -0
- package/state/Coalesce.luau +43 -0
- package/state/Fieldset.luau +177 -0
- package/state/Newest.luau +339 -0
- package/state/Plan.luau +441 -0
- package/state/Sections.luau +468 -0
- package/state/Store.luau +188 -0
- package/state/Sync.luau +762 -0
- package/wire/Bytes.luau +118 -0
- package/wire/Clock.luau +37 -0
- package/wire/Protocol.luau +110 -0
- package/wire/Sequence.luau +40 -0
- package/wire/Varint.luau +124 -0
- package/src/Types.luau +0 -180
- package/src/api/Group.luau +0 -156
- package/src/api/Packet.luau +0 -319
- package/src/api/Query.luau +0 -338
- package/src/api/Scope.luau +0 -90
- package/src/api/Signal.luau +0 -188
- package/src/codec/Base.luau +0 -136
- package/src/codec/composite/Array.luau +0 -456
- package/src/codec/composite/Map.luau +0 -469
- package/src/codec/composite/Optional.luau +0 -54
- package/src/codec/composite/Shared.luau +0 -291
- package/src/codec/composite/Struct.luau +0 -494
- package/src/codec/composite/Tagged.luau +0 -103
- package/src/codec/composite/Tuple.luau +0 -143
- package/src/codec/datatype/Buffer.luau +0 -66
- package/src/codec/datatype/CFrame.luau +0 -109
- package/src/codec/datatype/Color.luau +0 -32
- package/src/codec/datatype/Instance.luau +0 -52
- package/src/codec/datatype/IntVector.luau +0 -39
- package/src/codec/datatype/NumberRange.luau +0 -39
- package/src/codec/datatype/Ray.luau +0 -36
- package/src/codec/datatype/Rect.luau +0 -31
- package/src/codec/datatype/Region.luau +0 -62
- package/src/codec/datatype/Sequence.luau +0 -184
- package/src/codec/datatype/String.luau +0 -94
- package/src/codec/datatype/UDim.luau +0 -46
- package/src/codec/datatype/Vector.luau +0 -130
- package/src/codec/meta/Auto.luau +0 -318
- package/src/codec/meta/Bitfield.luau +0 -147
- package/src/codec/meta/Custom.luau +0 -33
- package/src/codec/meta/DeltaScalar.luau +0 -390
- package/src/codec/meta/Enum.luau +0 -50
- package/src/codec/meta/Float.luau +0 -38
- package/src/codec/meta/Nothing.luau +0 -13
- package/src/codec/meta/Unknown.luau +0 -41
- package/src/codec/primitive/Bool.luau +0 -26
- package/src/codec/primitive/Float16.luau +0 -99
- package/src/codec/primitive/Int.luau +0 -59
- package/src/codec/primitive/Number.luau +0 -24
- package/src/codec/primitive/Signed.luau +0 -32
- package/src/codec/primitive/Varint.luau +0 -165
- package/src/codec/primitive/Zint.luau +0 -99
- package/src/index.d.ts +0 -423
- package/src/init.luau +0 -362
- package/src/internal/Baseline.luau +0 -57
- package/src/internal/Channel.luau +0 -390
- package/src/internal/Middleware.luau +0 -100
- package/src/internal/Pool.luau +0 -65
- package/src/internal/Registry.luau +0 -119
- package/src/internal/Transport.luau +0 -28
- package/src/transport/Bridge.luau +0 -110
- package/src/transport/Client.luau +0 -97
- package/src/transport/Gate.luau +0 -488
- package/src/transport/Reader.luau +0 -331
- package/src/transport/Server.luau +0 -211
- package/src/util/Array.luau +0 -18
- package/src/util/Buffer.luau +0 -90
- package/src/util/Constants.luau +0 -30
- package/src/util/Log.luau +0 -68
- package/src/util/Player.luau +0 -14
- package/src/util/Quantize.luau +0 -84
- package/src/util/Quat.luau +0 -124
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- A namespace of declarations as the frozen records every layer above reads it by.
|
|
4
|
+
|
|
5
|
+
local Base = require (script.Parent.Parent.codec.Base)
|
|
6
|
+
local Frames = require (script.Parent.Frames)
|
|
7
|
+
local Legality = require (script.Parent.Legality)
|
|
8
|
+
local Log = require (script.Parent.Parent.kernel.Log)
|
|
9
|
+
local Order = require (script.Parent.Order)
|
|
10
|
+
local Serial = require (script.Parent.Serial)
|
|
11
|
+
local Shape = require (script.Parent)
|
|
12
|
+
local Types = require (script.Parent.Parent.Types)
|
|
13
|
+
local Wide = require (script.Parent.Parent.kernel.Wide)
|
|
14
|
+
|
|
15
|
+
local Compile = {}
|
|
16
|
+
|
|
17
|
+
-- Constants -----------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
-- What a template holds in every field, which is a place rather than a value.
|
|
20
|
+
const PLACE = false
|
|
21
|
+
|
|
22
|
+
-- Types ---------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
-- What one definition costs, as the two numbers a caller of it can want.
|
|
25
|
+
export type Packet = {
|
|
26
|
+
read id: number,
|
|
27
|
+
read name: string,
|
|
28
|
+
read kind: "packet",
|
|
29
|
+
read maxBytes: number,
|
|
30
|
+
read file: string,
|
|
31
|
+
read line: number,
|
|
32
|
+
read built: Shape.Built,
|
|
33
|
+
read head: Frames.Head,
|
|
34
|
+
read blockBytes: number,
|
|
35
|
+
read delivery: Serial.Delivery,
|
|
36
|
+
read hz: number?,
|
|
37
|
+
read timestamped: boolean,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
--[[
|
|
41
|
+
A query holds two builds and one id, and its response is that id and one. A frame carries a
|
|
42
|
+
single axis and no kind bit, so which half arrived is read off whether the id is the one the
|
|
43
|
+
record carries, a comparison the router already holds both sides of.
|
|
44
|
+
]]
|
|
45
|
+
export type Query = {
|
|
46
|
+
read id: number,
|
|
47
|
+
read name: string,
|
|
48
|
+
read kind: "query",
|
|
49
|
+
read maxBytes: number,
|
|
50
|
+
read file: string,
|
|
51
|
+
read line: number,
|
|
52
|
+
read request: Shape.Built,
|
|
53
|
+
read response: Shape.Built,
|
|
54
|
+
read asks: Frames.Head,
|
|
55
|
+
read answers: Frames.Head,
|
|
56
|
+
read blockBytes: number,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
--[[
|
|
60
|
+
A set is its fields, so what it carries is per field and in one order. The record's own cell is
|
|
61
|
+
here and its own build is not, since a section never writes a whole record and the cell is all
|
|
62
|
+
the descriptor ever wanted. Which fields may hold nothing and which may only climb are beside
|
|
63
|
+
the builds, because reading either off a cell at the call would be `state` reading a codec.
|
|
64
|
+
]]
|
|
65
|
+
export type Set = {
|
|
66
|
+
read id: number,
|
|
67
|
+
read name: string,
|
|
68
|
+
read kind: "set",
|
|
69
|
+
read maxBytes: number,
|
|
70
|
+
read file: string,
|
|
71
|
+
read line: number,
|
|
72
|
+
read cell: Base.Cell,
|
|
73
|
+
read head: Frames.Head,
|
|
74
|
+
read stream: Frames.Head,
|
|
75
|
+
read keyField: string?,
|
|
76
|
+
read keyIndex: number?,
|
|
77
|
+
read fieldNames: { string },
|
|
78
|
+
read fieldIndex: { [string]: number },
|
|
79
|
+
read fieldBuilt: { Shape.Built },
|
|
80
|
+
read fieldCount: number,
|
|
81
|
+
read newestFields: { number },
|
|
82
|
+
read optionalFields: { boolean },
|
|
83
|
+
read climbingFields: { boolean },
|
|
84
|
+
read template: { [string]: any },
|
|
85
|
+
read site: Shape.Site,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
-- The marker vocabulary, re-exported rather than reached for.
|
|
89
|
+
export type Marker = Base.Marker
|
|
90
|
+
|
|
91
|
+
export type Def = Packet | Query | Set
|
|
92
|
+
|
|
93
|
+
--[[
|
|
94
|
+
A namespace, compiled. `count` is how many ids were handed out rather than how many definitions
|
|
95
|
+
there are, because a defId is a ranged int over exactly that and a query took two.
|
|
96
|
+
]]
|
|
97
|
+
export type Compiled = {
|
|
98
|
+
read space: string,
|
|
99
|
+
read descriptor: string,
|
|
100
|
+
read hash: Wide.Word,
|
|
101
|
+
read count: number,
|
|
102
|
+
read list: { Def },
|
|
103
|
+
read byName: { [string]: Def },
|
|
104
|
+
read byId: { [number]: Def },
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
-- A set's fields, as the four arrays a column walk reads and the bytes one record comes to.
|
|
108
|
+
type Fields = {
|
|
109
|
+
names: { string },
|
|
110
|
+
index: { [string]: number },
|
|
111
|
+
built: { Shape.Built },
|
|
112
|
+
newest: { number },
|
|
113
|
+
optional: { boolean },
|
|
114
|
+
climbs: { boolean },
|
|
115
|
+
template: { [string]: any },
|
|
116
|
+
site: Shape.Site,
|
|
117
|
+
bytes: number,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
-- Private -------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
-- A handle as the declaration it carries.
|
|
123
|
+
local function declared (of: Types.Definition): Legality.Declared return of :: any end
|
|
124
|
+
|
|
125
|
+
-- A set's fields, in the order their columns are indexed by.
|
|
126
|
+
local function columns (name: string, cell: Base.Cell): Fields
|
|
127
|
+
local fields = cell.children :: { [string]: Base.Cell }
|
|
128
|
+
local names = Order.names (fields)
|
|
129
|
+
local reach = #names
|
|
130
|
+
|
|
131
|
+
local built = table.create (reach) :: { Shape.Built }
|
|
132
|
+
local place: { [string]: number } = {}
|
|
133
|
+
local newest: { number } = {}
|
|
134
|
+
local optional = table.create (reach) :: { boolean }
|
|
135
|
+
local climbs = table.create (reach) :: { boolean }
|
|
136
|
+
local template: { [string]: any } = {}
|
|
137
|
+
local bytes = 0
|
|
138
|
+
|
|
139
|
+
--[[
|
|
140
|
+
One site for the whole set rather than one a field, everything in it numbered from
|
|
141
|
+
nothing. A section is one block over every field and a boundary holds the definition, so
|
|
142
|
+
fields numbering into tables of their own would each start again at one.
|
|
143
|
+
]]
|
|
144
|
+
local site: Shape.Site = {
|
|
145
|
+
paths = Serial.interner (),
|
|
146
|
+
expected = Serial.interner (),
|
|
147
|
+
sidecar = { refs = {}, slotOf = {}, bears = false },
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
for index, field in names do
|
|
151
|
+
local held = fields[field]
|
|
152
|
+
local one = Shape.build (Base.codec (held), Serial.under (name, field), site)
|
|
153
|
+
|
|
154
|
+
built[index] = one
|
|
155
|
+
place[field] = index
|
|
156
|
+
bytes += one.maxBytes
|
|
157
|
+
template[field] = PLACE
|
|
158
|
+
optional[index] = held.kind == "optional"
|
|
159
|
+
climbs[index] = held.marker == "monotonic"
|
|
160
|
+
|
|
161
|
+
if held.marker == "newest" then table.insert (newest, index) end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
names = table.freeze (names),
|
|
166
|
+
index = table.freeze (place),
|
|
167
|
+
built = table.freeze (built),
|
|
168
|
+
newest = table.freeze (newest),
|
|
169
|
+
optional = table.freeze (optional),
|
|
170
|
+
climbs = table.freeze (climbs),
|
|
171
|
+
template = table.freeze (template),
|
|
172
|
+
site = site,
|
|
173
|
+
bytes = bytes,
|
|
174
|
+
}
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
-- One declaration as the record it becomes, at the id and under the count it was given.
|
|
178
|
+
local function made (name: string, id: number, over: number, of: Legality.Declared): Def
|
|
179
|
+
local at = of.at
|
|
180
|
+
|
|
181
|
+
if of.kind == "packet" then
|
|
182
|
+
local built = Shape.build (of.of, name)
|
|
183
|
+
local lane = Legality.delivery (of)
|
|
184
|
+
|
|
185
|
+
--[[
|
|
186
|
+
A newest packet's block is a different form rather than the same one differently filled:
|
|
187
|
+
it carries a sequence and never a continuation, because its senders coalesce to one
|
|
188
|
+
value before it is sequenced and a bit saying so would never be anything else.
|
|
189
|
+
]]
|
|
190
|
+
local head = if lane == "newest"
|
|
191
|
+
then Frames.newest (over, of.isTimestamped)
|
|
192
|
+
else Frames.packet (over, of.isTimestamped)
|
|
193
|
+
|
|
194
|
+
local bytes = Frames.block (head, built.maxBytes)
|
|
195
|
+
Legality.block (name, of, bytes)
|
|
196
|
+
|
|
197
|
+
return table.freeze ({
|
|
198
|
+
id = id,
|
|
199
|
+
name = name,
|
|
200
|
+
kind = "packet" :: "packet",
|
|
201
|
+
maxBytes = built.maxBytes,
|
|
202
|
+
file = at.file,
|
|
203
|
+
line = at.line,
|
|
204
|
+
built = built,
|
|
205
|
+
head = head,
|
|
206
|
+
blockBytes = bytes,
|
|
207
|
+
delivery = lane,
|
|
208
|
+
hz = of.hz,
|
|
209
|
+
timestamped = of.isTimestamped,
|
|
210
|
+
})
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
--[[
|
|
214
|
+
A query is two blocks at two ids, so it is two heads, and what one costs is the wider of
|
|
215
|
+
them. Neither is held to a ceiling: both ride the reliable lane, which is never split and is
|
|
216
|
+
bounded by the budget rather than by what one fire carries.
|
|
217
|
+
]]
|
|
218
|
+
if of.kind == "query" then
|
|
219
|
+
local request = Shape.build (of.of, Serial.under (name, Legality.REQUEST))
|
|
220
|
+
local response = Shape.build (of.reply, Serial.under (name, Legality.RESPONSE))
|
|
221
|
+
|
|
222
|
+
local asks = Frames.request (over)
|
|
223
|
+
local answers = Frames.response (over)
|
|
224
|
+
|
|
225
|
+
return table.freeze ({
|
|
226
|
+
id = id,
|
|
227
|
+
name = name,
|
|
228
|
+
kind = "query" :: "query",
|
|
229
|
+
maxBytes = math.max (request.maxBytes, response.maxBytes),
|
|
230
|
+
file = at.file,
|
|
231
|
+
line = at.line,
|
|
232
|
+
request = request,
|
|
233
|
+
response = response,
|
|
234
|
+
asks = asks,
|
|
235
|
+
answers = answers,
|
|
236
|
+
blockBytes = math.max (
|
|
237
|
+
Frames.block (asks, request.maxBytes),
|
|
238
|
+
Frames.block (answers, response.maxBytes)
|
|
239
|
+
),
|
|
240
|
+
})
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
local cell = Base.cell (of.of)
|
|
244
|
+
local held = columns (name, cell)
|
|
245
|
+
local key = of.keyField
|
|
246
|
+
|
|
247
|
+
return table.freeze ({
|
|
248
|
+
id = id,
|
|
249
|
+
name = name,
|
|
250
|
+
kind = "set" :: "set",
|
|
251
|
+
maxBytes = held.bytes,
|
|
252
|
+
file = at.file,
|
|
253
|
+
line = at.line,
|
|
254
|
+
cell = cell,
|
|
255
|
+
head = Frames.section (over),
|
|
256
|
+
stream = Frames.stream (over, #held.names),
|
|
257
|
+
keyField = key,
|
|
258
|
+
keyIndex = if key == nil then nil else held.index[key],
|
|
259
|
+
fieldNames = held.names,
|
|
260
|
+
fieldIndex = held.index,
|
|
261
|
+
fieldBuilt = held.built,
|
|
262
|
+
site = held.site,
|
|
263
|
+
fieldCount = #held.names,
|
|
264
|
+
newestFields = held.newest,
|
|
265
|
+
optionalFields = held.optional,
|
|
266
|
+
climbingFields = held.climbs,
|
|
267
|
+
template = held.template,
|
|
268
|
+
})
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
-- A definition as the descriptor writes it.
|
|
272
|
+
local function framed (of: Def): Serial.Frame
|
|
273
|
+
if of.kind == "packet" then
|
|
274
|
+
return {
|
|
275
|
+
kind = "packet",
|
|
276
|
+
of = of.built,
|
|
277
|
+
delivery = of.delivery,
|
|
278
|
+
hz = of.hz,
|
|
279
|
+
timestamped = of.timestamped,
|
|
280
|
+
}
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
if of.kind == "query" then return { kind = "query", of = of.request, reply = of.response } end
|
|
284
|
+
return { kind = "set", of = { cell = of.cell }, keyField = of.keyField }
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
-- Public --------------------------------------------------------------
|
|
288
|
+
|
|
289
|
+
-- A namespace's declarations, refused or compiled, as one frozen record.
|
|
290
|
+
function Compile.build (space: string, specs: Types.Definitions): Compiled
|
|
291
|
+
local why = Legality.named (space)
|
|
292
|
+
if why ~= nil then Log.refuse (`the namespace {space} {why}`) end
|
|
293
|
+
|
|
294
|
+
local names = Order.names (specs)
|
|
295
|
+
|
|
296
|
+
-- How many ids there are, before any of them is handed out.
|
|
297
|
+
local over = 0
|
|
298
|
+
for _, name in names do
|
|
299
|
+
over += if declared (specs[name]).kind == "query" then 2 else 1
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
local list = table.create (#names) :: { Def }
|
|
303
|
+
local byName: { [string]: Def } = {}
|
|
304
|
+
local byId: { [number]: Def } = {}
|
|
305
|
+
local frames: { [string]: Serial.Frame } = {}
|
|
306
|
+
|
|
307
|
+
local at = 0
|
|
308
|
+
for _, name in names do
|
|
309
|
+
local of = declared (specs[name])
|
|
310
|
+
Legality.definition (name, of)
|
|
311
|
+
|
|
312
|
+
local def = made (name, at, over, of)
|
|
313
|
+
table.insert (list, def)
|
|
314
|
+
byName[name] = def
|
|
315
|
+
frames[name] = framed (def)
|
|
316
|
+
|
|
317
|
+
byId[at] = def
|
|
318
|
+
if def.kind ~= "query" then
|
|
319
|
+
at += 1
|
|
320
|
+
continue
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
byId[at + 1] = def
|
|
324
|
+
at += 2
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
local descriptor = Serial.namespace (space, frames)
|
|
328
|
+
|
|
329
|
+
return table.freeze ({
|
|
330
|
+
space = space,
|
|
331
|
+
descriptor = descriptor,
|
|
332
|
+
hash = Serial.hash (descriptor),
|
|
333
|
+
count = over,
|
|
334
|
+
list = table.freeze (list),
|
|
335
|
+
byName = table.freeze (byName),
|
|
336
|
+
byId = table.freeze (byId),
|
|
337
|
+
})
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
return table.freeze (Compile)
|
package/shape/Folds.luau
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- A declaration whose value comes apart by a computation, as the leaves it takes and the pair.
|
|
4
|
+
|
|
5
|
+
local Base = require (script.Parent.Parent.codec.Base)
|
|
6
|
+
local Grid = require (script.Parent.Grid)
|
|
7
|
+
local Ir = require (script.Parent.Ir)
|
|
8
|
+
local Joins = require (script.Parent.Joins)
|
|
9
|
+
local Protocol = require (script.Parent.Parent.wire.Protocol)
|
|
10
|
+
local Rotation = require (script.Parent.Rotation)
|
|
11
|
+
local Scalars = require (script.Parent.Parent.codec.Scalars)
|
|
12
|
+
|
|
13
|
+
local Folds = {}
|
|
14
|
+
|
|
15
|
+
-- Types ---------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
-- What a fold becomes, which is what a field the language carries becomes and for one reason.
|
|
18
|
+
export type Field = Joins.Field
|
|
19
|
+
|
|
20
|
+
-- Constants -----------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
-- What the engine calls each of the four this file takes apart.
|
|
23
|
+
const PLANE = "Vector2"
|
|
24
|
+
const VECTOR = "Vector3"
|
|
25
|
+
const FRAME = "CFrame"
|
|
26
|
+
const COLOUR = "Color3"
|
|
27
|
+
|
|
28
|
+
-- The same four, under the kinds that declare them.
|
|
29
|
+
Folds.ENGINE = table.freeze ({
|
|
30
|
+
vec2 = PLANE,
|
|
31
|
+
vec3 = VECTOR,
|
|
32
|
+
color3 = COLOUR,
|
|
33
|
+
cframe = FRAME,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
-- The four a smallest three chooses between, which is what its tag is a ranged int over.
|
|
37
|
+
const CORNERS = Protocol.QUAT_W + 1
|
|
38
|
+
|
|
39
|
+
-- How far past its first leaf the last of those four sits.
|
|
40
|
+
const LAST = CORNERS - 1
|
|
41
|
+
|
|
42
|
+
-- What a packed colour spends on each of its three, which is named one at a time.
|
|
43
|
+
const RED = Protocol.RGB565_RED
|
|
44
|
+
const GREEN = Protocol.RGB565_GREEN
|
|
45
|
+
const BLUE = Protocol.RGB565_BLUE
|
|
46
|
+
|
|
47
|
+
-- Private -------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
-- A fold, as the one shape every form below answers in.
|
|
50
|
+
export type Fold = {
|
|
51
|
+
leaves: { Grid.Grid },
|
|
52
|
+
pull: (value: any, into: { number }, at: number) -> boolean,
|
|
53
|
+
push: (from: { number }, at: number) -> any,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
-- The components of a vector, one grid each, in the order they are written.
|
|
57
|
+
local function spread (of: Grid.Grid, wide: boolean): Fold
|
|
58
|
+
local toIndex, fromIndex = of.toIndex, of.fromIndex
|
|
59
|
+
|
|
60
|
+
local leaves = if wide then { of, of, of } else { of, of }
|
|
61
|
+
|
|
62
|
+
-- Both widths come through here, so what it is handed is whichever the leaves say it took.
|
|
63
|
+
local wanted = if wide then VECTOR else PLANE
|
|
64
|
+
|
|
65
|
+
local function pull (value: any, into: { number }, at: number): boolean
|
|
66
|
+
if typeof (value) ~= wanted then return false end
|
|
67
|
+
|
|
68
|
+
local x, y = toIndex (value.X), toIndex (value.Y)
|
|
69
|
+
if x == nil or y == nil then return false end
|
|
70
|
+
|
|
71
|
+
if not wide then
|
|
72
|
+
into[at], into[at + 1] = x, y
|
|
73
|
+
return true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
local z = toIndex (value.Z)
|
|
77
|
+
if z == nil then return false end
|
|
78
|
+
|
|
79
|
+
into[at], into[at + 1], into[at + 2] = x, y, z
|
|
80
|
+
return true
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
local function push (from: { number }, at: number): any
|
|
84
|
+
if not wide then return Vector2.new (fromIndex (from[at]), fromIndex (from[at + 1])) end
|
|
85
|
+
local x, y = fromIndex (from[at]), fromIndex (from[at + 1])
|
|
86
|
+
return Vector3.new (x, y, fromIndex (from[at + 2]))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
return { leaves = leaves, pull = pull, push = push }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
-- A direction as the two the octahedral fold keeps, which is `vec3.unit` and nothing else.
|
|
93
|
+
local function pointing (of: Grid.Grid): Fold
|
|
94
|
+
local mapping = Rotation.octahedral (of)
|
|
95
|
+
local plane, sphere = mapping.plane, mapping.sphere
|
|
96
|
+
|
|
97
|
+
local function pull (value: any, into: { number }, at: number): boolean
|
|
98
|
+
if typeof (value) ~= VECTOR then return false end
|
|
99
|
+
|
|
100
|
+
local u, v = plane (value.X, value.Y, value.Z)
|
|
101
|
+
if u == nil or v == nil then return false end
|
|
102
|
+
|
|
103
|
+
into[at], into[at + 1] = u, v
|
|
104
|
+
return true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
local function push (from: { number }, at: number): any
|
|
108
|
+
return Vector3.new (sphere (from[at], from[at + 1]))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
return { leaves = { of, of }, pull = pull, push = push }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
--[[
|
|
115
|
+
A direction and how far it reaches, the one form whose leaves are two grids. The length is
|
|
116
|
+
worked out and never read off the value, so nothing in this file asks a datatype for anything
|
|
117
|
+
but its components.
|
|
118
|
+
]]
|
|
119
|
+
local function reaching (way: Grid.Grid, far: Grid.Grid): Fold
|
|
120
|
+
local mapping = Rotation.octahedral (way)
|
|
121
|
+
local plane, sphere = mapping.plane, mapping.sphere
|
|
122
|
+
local toIndex, fromIndex = far.toIndex, far.fromIndex
|
|
123
|
+
|
|
124
|
+
--[[
|
|
125
|
+
Where a vector of no length points, which is nowhere and has to be somewhere. The fold
|
|
126
|
+
divides by the sum of the magnitudes, so a zero would reach the grid as no place at all.
|
|
127
|
+
The middle of the square is what it takes, which multiplies back out to the zero it was.
|
|
128
|
+
]]
|
|
129
|
+
local centre = way.toIndex (0) :: number
|
|
130
|
+
|
|
131
|
+
local function pull (value: any, into: { number }, at: number): boolean
|
|
132
|
+
if typeof (value) ~= VECTOR then return false end
|
|
133
|
+
|
|
134
|
+
local x, y, z = value.X, value.Y, value.Z
|
|
135
|
+
local length = toIndex (math.sqrt (x * x + y * y + z * z))
|
|
136
|
+
if length == nil then return false end
|
|
137
|
+
|
|
138
|
+
--[[
|
|
139
|
+
A vector whose length comes to none, which is every vector shorter than half a step and
|
|
140
|
+
not only the one that arrived as a zero.
|
|
141
|
+
]]
|
|
142
|
+
if fromIndex (length) == 0 then
|
|
143
|
+
into[at], into[at + 1], into[at + 2] = centre, centre, length
|
|
144
|
+
return true
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
local u, v = plane (x, y, z)
|
|
148
|
+
if u == nil or v == nil then return false end
|
|
149
|
+
|
|
150
|
+
into[at], into[at + 1], into[at + 2] = u, v, length
|
|
151
|
+
return true
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
local function push (from: { number }, at: number): any
|
|
155
|
+
local x, y, z = sphere (from[at], from[at + 1])
|
|
156
|
+
local length = fromIndex (from[at + 2])
|
|
157
|
+
|
|
158
|
+
return Vector3.new (x * length, y * length, z * length)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
return { leaves = { way, way, far }, pull = pull, push = push }
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
-- A frame that turns about nothing, which occupies no leaves at all.
|
|
165
|
+
local function still (): Fold
|
|
166
|
+
local function pull (): boolean return true end
|
|
167
|
+
local function push (): any return CFrame.identity end
|
|
168
|
+
|
|
169
|
+
return { leaves = {}, pull = pull, push = push }
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
-- A frame as the one number every rotation form here comes back through, which is a quaternion.
|
|
173
|
+
local function turned (leaves: { Grid.Grid }, parts: any, whole: any, reach: number): Fold
|
|
174
|
+
local function pull (value: any, into: { number }, at: number): boolean
|
|
175
|
+
if typeof (value) ~= FRAME then return false end
|
|
176
|
+
|
|
177
|
+
local first, second, third, fourth = parts (value:GetComponents ())
|
|
178
|
+
if first == nil then return false end
|
|
179
|
+
|
|
180
|
+
into[at] = first :: number
|
|
181
|
+
if reach == 1 then return true end
|
|
182
|
+
|
|
183
|
+
if second == nil then return false end
|
|
184
|
+
into[at + 1] = second :: number
|
|
185
|
+
if reach == 2 then return true end
|
|
186
|
+
|
|
187
|
+
if third == nil or fourth == nil then return false end
|
|
188
|
+
into[at + 2], into[at + LAST] = third :: number, fourth :: number
|
|
189
|
+
return true
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
local function push (from: { number }, at: number): any
|
|
193
|
+
local x, y, z, w = whole (from[at], from[at + 1], from[at + 2], from[at + LAST])
|
|
194
|
+
return CFrame.new (0, 0, 0, x, y, z, w)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
return { leaves = leaves, pull = pull, push = push }
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
-- The three a packed colour spends its sixteen bits on, red first and least.
|
|
201
|
+
local function packed (): Fold
|
|
202
|
+
local red, green, blue = Grid.channel (RED), Grid.channel (GREEN), Grid.channel (BLUE)
|
|
203
|
+
|
|
204
|
+
local function pull (value: any, into: { number }, at: number): boolean
|
|
205
|
+
if typeof (value) ~= COLOUR then return false end
|
|
206
|
+
|
|
207
|
+
local r, g, b = red.toIndex (value.R), green.toIndex (value.G), blue.toIndex (value.B)
|
|
208
|
+
if r == nil or g == nil or b == nil then return false end
|
|
209
|
+
|
|
210
|
+
into[at], into[at + 1], into[at + 2] = r, g, b
|
|
211
|
+
return true
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
local function push (from: { number }, at: number): any
|
|
215
|
+
return Color3.new (
|
|
216
|
+
red.fromIndex (from[at]),
|
|
217
|
+
green.fromIndex (from[at + 1]),
|
|
218
|
+
blue.fromIndex (from[at + 2])
|
|
219
|
+
)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
return { leaves = { red, green, blue }, pull = pull, push = push }
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
-- One of a list of colours, as where it sits in the list.
|
|
226
|
+
local function chosen (colors: { Color3 }): Fold
|
|
227
|
+
local reach = #colors
|
|
228
|
+
local of = Grid.index (reach)
|
|
229
|
+
|
|
230
|
+
local index: { [string]: number } = {}
|
|
231
|
+
for place, one in colors do
|
|
232
|
+
index[`{one.R},{one.G},{one.B}`] = place - 1
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
local function pull (value: any, into: { number }, at: number): boolean
|
|
236
|
+
if typeof (value) ~= COLOUR then return false end
|
|
237
|
+
|
|
238
|
+
local held = index[`{value.R},{value.G},{value.B}`]
|
|
239
|
+
if held == nil then return false end
|
|
240
|
+
|
|
241
|
+
into[at] = held
|
|
242
|
+
return true
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
local function push (from: { number }, at: number): any return colors[from[at] + 1] end
|
|
246
|
+
|
|
247
|
+
return { leaves = { of }, pull = pull, push = push }
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
-- Public --------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
-- Which fold a declaration is, or nothing where it is no region field at all.
|
|
253
|
+
function Folds.fold (of: Base.Cell): Fold?
|
|
254
|
+
local kind, params = of.kind, of.params
|
|
255
|
+
local form = params.form
|
|
256
|
+
|
|
257
|
+
if kind == "vec2" or kind == "vec3" then
|
|
258
|
+
local children = of.children
|
|
259
|
+
local component = if children == nil then nil else children.component
|
|
260
|
+
|
|
261
|
+
if form == "unit" then return pointing (Grid.plane (params.step :: number)) end
|
|
262
|
+
if form == "bounded" then
|
|
263
|
+
local max, step = params.max :: number, params.step :: number
|
|
264
|
+
return reaching (Grid.of (-1, 1, step / max), Grid.of (0, max, step))
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
if component == nil then return nil end
|
|
268
|
+
|
|
269
|
+
local single = Joins.grid (component)
|
|
270
|
+
if single == nil then return nil end
|
|
271
|
+
|
|
272
|
+
return spread (single, kind == "vec3")
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
if kind == "rotation" then
|
|
276
|
+
if form == "none" then return still () end
|
|
277
|
+
|
|
278
|
+
local step = params.step :: number
|
|
279
|
+
if form == "axis" then
|
|
280
|
+
local axis = params.axis :: Vector3
|
|
281
|
+
local grid = Grid.of (0, Scalars.TURN - step, step, true)
|
|
282
|
+
local mapping = Rotation.axial (grid, axis.X, axis.Y, axis.Z)
|
|
283
|
+
|
|
284
|
+
return turned ({ grid }, mapping.parts, mapping.whole, 1)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
if form == "direction" then
|
|
288
|
+
local grid = Grid.plane (step)
|
|
289
|
+
local mapping = Rotation.facing (grid)
|
|
290
|
+
|
|
291
|
+
return turned ({ grid, grid }, mapping.parts, mapping.whole, 2)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
local chord = Grid.chord (step)
|
|
295
|
+
local mapping = Rotation.smallest (chord)
|
|
296
|
+
|
|
297
|
+
return turned (
|
|
298
|
+
{ Grid.index (CORNERS), chord, chord, chord },
|
|
299
|
+
mapping.parts,
|
|
300
|
+
mapping.whole,
|
|
301
|
+
4
|
|
302
|
+
)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
if kind ~= "color3" then return nil end
|
|
306
|
+
|
|
307
|
+
if form == "rgb565" then return packed () end
|
|
308
|
+
if form == "palette" then return chosen (params.colors :: { Color3 }) end
|
|
309
|
+
|
|
310
|
+
return nil
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
-- A declaration, at the leaf it starts on, as the field it becomes.
|
|
314
|
+
function Folds.of (of: Base.Cell, tag: Ir.Tag, at: number, key: string?, nest: number?): Field?
|
|
315
|
+
local held = Folds.fold (of)
|
|
316
|
+
if held == nil then return nil end
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
leaves = held.leaves,
|
|
320
|
+
join = {
|
|
321
|
+
at = at,
|
|
322
|
+
count = #held.leaves,
|
|
323
|
+
key = key,
|
|
324
|
+
nest = nest,
|
|
325
|
+
tag = tag,
|
|
326
|
+
pull = held.pull,
|
|
327
|
+
push = held.push,
|
|
328
|
+
},
|
|
329
|
+
}
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
return table.freeze (Folds)
|