cluaupp 1.4.1 → 1.5.1
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/CHANGELOG.md +55 -0
- package/README.md +10 -5
- package/api/CHANGELOG.md +3 -0
- package/api/chat.js +74 -0
- package/api/fixtures/roblox/README.md +6 -0
- package/api/fixtures/roblox/aux/sample.d.luau +6 -0
- package/api/fixtures/roblox/mini/Mini-API-Dump.json +72 -0
- package/api/generated/bench-latest.json +39 -0
- package/api/generated/capability-profile.json +76 -0
- package/api/generated/lsp-index.json +1 -0
- package/api/generated/luau/classes.d.luau +11221 -0
- package/api/generated/luau/datatypes.d.luau +327 -0
- package/api/generated/luau/enums.d.luau +4918 -0
- package/api/generated/luau/globals.d.luau +12 -0
- package/api/manifests/roblox-target.manifest.json +22 -0
- package/api/normalized/roblox-target.profile.json +237461 -0
- package/api/overrides/classes.json +8 -0
- package/api/overrides/compatibility.json +9 -0
- package/api/overrides/datatypes.json +1579 -0
- package/api/overrides/enums.json +8 -0
- package/api/overrides/globals.json +8 -0
- package/api/overrides/type-mappings.json +9 -0
- package/api/roblox-api.lock.json +9 -0
- package/data/Mini-API-Dump.json +1 -0
- package/editors/vscode/README.md +19 -0
- package/editors/vscode/extension.js +222 -21
- package/editors/vscode/icons/axiom.svg +4 -0
- package/editors/vscode/icons/bloom.svg +5 -0
- package/editors/vscode/icons/flare.svg +5 -0
- package/editors/vscode/icons/helm.svg +4 -0
- package/editors/vscode/icons/hive.svg +5 -0
- package/editors/vscode/icons/mint.svg +4 -0
- package/editors/vscode/icons/shift.svg +6 -0
- package/editors/vscode/language-configuration-schema.json +24 -0
- package/editors/vscode/language-configuration.json +21 -0
- package/editors/vscode/package.json +220 -6
- package/editors/vscode/snippets/axiom.json +12 -0
- package/editors/vscode/snippets/bloom.json +12 -0
- package/editors/vscode/snippets/flare.json +27 -0
- package/editors/vscode/snippets/helm.json +12 -0
- package/editors/vscode/snippets/hive.json +12 -0
- package/editors/vscode/snippets/mint.json +12 -0
- package/editors/vscode/snippets/shift.json +17 -0
- package/editors/vscode/syntaxes/axiom.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/bloom.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/flare.tmLanguage.json +75 -0
- package/editors/vscode/syntaxes/helm.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/hive.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/mint.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/schema.tmLanguage.json +89 -0
- package/editors/vscode/syntaxes/shift.tmLanguage.json +5 -0
- package/examples/game/.cluaupp/compile-cache/ReplicatedStorage__Shared__Constants__Datas__TemplateData.clh.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Boot__DataBoot.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Configuration__ServerConfig.clp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__Guard.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__PlayerHandler.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterCharacterScripts__Character__CharacterReady.client.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterPlayerScripts__Controllers__DataController.client.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/index.json +12 -0
- package/examples/game/.cluaupp/datamodel-profile.json +94 -0
- package/examples/game/.vscode/extensions.json +3 -1
- package/examples/game/.vscode/settings.json +13 -1
- package/examples/game/include/clpp/datatypes.clh +337 -373
- package/examples/game/include/clpp/generated/datamodel.clh +25 -0
- package/examples/game/include/clpp/generated/enums.clh +1 -1
- package/examples/game/include/clpp/generated/instances.clh +41135 -41064
- package/examples/game/include/clpp/libs/axiom.clh +1 -1
- package/examples/game/include/clpp/libs/math.clh +14 -0
- package/examples/game/include/clpp/libs/roster.clh +6 -0
- package/examples/game/include/clpp/libs/spring.clh +17 -0
- package/examples/game/include/clpp/libs/ward.clh +1 -0
- package/examples/game/include/clpp/roblox.clh +3 -4
- package/examples/game/libs/ArrayIndexer/init.luau +209 -0
- package/examples/game/libs/Axiom/init.luau +608 -0
- package/examples/game/libs/Bloom/init.luau +433 -0
- package/examples/game/libs/Coil/init.luau +215 -0
- package/examples/game/libs/Crest/init.luau +426 -0
- package/examples/game/libs/Echo/init.luau +417 -0
- package/examples/game/libs/Ember/init.luau +365 -0
- package/examples/game/libs/Flare/init.luau +717 -0
- package/examples/game/libs/Gleam/init.luau +729 -0
- package/examples/game/libs/Guide/init.luau +215 -0
- package/examples/game/libs/Helm/init.luau +377 -0
- package/examples/game/libs/Hive/init.luau +241 -0
- package/examples/game/libs/Keep/Client.luau +114 -0
- package/examples/game/libs/Keep/Data.luau +883 -0
- package/examples/game/libs/Keep/Engine.luau +211 -0
- package/examples/game/libs/Keep/Enum.luau +6 -0
- package/examples/game/libs/Keep/Enums.luau +10 -0
- package/examples/game/libs/Keep/Path.luau +236 -0
- package/examples/game/libs/Keep/Replicator.luau +298 -0
- package/examples/game/libs/Keep/Server.luau +251 -0
- package/examples/game/libs/Keep/Store.luau +652 -0
- package/examples/game/libs/Keep/Trade.luau +455 -0
- package/examples/game/libs/Keep/init.luau +205 -0
- package/examples/game/libs/Lens/init.luau +609 -0
- package/examples/game/libs/Mint/init.luau +279 -0
- package/examples/game/libs/Net/init.luau +156 -0
- package/examples/game/libs/Net/src/codec.luau +224 -0
- package/examples/game/libs/Occlude/init.luau +117 -0
- package/examples/game/libs/Pin/init.luau +309 -0
- package/examples/game/libs/Promise/LICENSE +21 -0
- package/examples/game/libs/Promise/_impl/LICENSE +21 -0
- package/examples/game/libs/Promise/_impl/init.lua +1991 -0
- package/examples/game/libs/Promise/init.lua +1990 -0
- package/examples/game/libs/Promise/init.luau +13 -0
- package/examples/game/libs/Promise/types.luau +46 -0
- package/examples/game/libs/Roster/init.luau +686 -0
- package/examples/game/libs/SOURCES.md +31 -0
- package/examples/game/libs/Shift/init.luau +238 -0
- package/examples/game/libs/Spark/init.luau +487 -0
- package/examples/game/libs/Stage/init.luau +178 -0
- package/examples/game/libs/Sweep/init.luau +259 -0
- package/examples/game/libs/Trace/init.luau +213 -0
- package/examples/game/libs/Ward/init.luau +211 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +29 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +13 -0
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +83 -0
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +18 -0
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +14 -0
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +15 -0
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +50 -0
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +12 -0
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +16 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +13 -0
- package/examples/game/src/ReplicatedStorage/Shared/Net/Net.clh +26 -0
- package/examples/game/src/ReplicatedStorage/Shared/Net/Net.flare +5 -0
- package/examples/game/src/ServerScriptService/Boot/DataBoot.server.clpp +2 -2
- package/examples/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
- package/examples/game/stylua.toml +9 -0
- package/generated/api/build-profile.js +115 -0
- package/generated/api/cache.js +44 -0
- package/generated/api/coverage.js +32 -0
- package/generated/api/diff.js +125 -0
- package/generated/api/generators/clpp-headers.js +353 -0
- package/generated/api/generators/docs-reference.js +7 -0
- package/generated/api/generators/lsp-index.js +81 -0
- package/generated/api/generators/luau-defs.js +94 -0
- package/generated/api/ide.js +76 -0
- package/generated/api/identifier.js +47 -0
- package/generated/api/index.js +324 -0
- package/generated/api/loader.js +57 -0
- package/generated/api/merge.js +88 -0
- package/generated/api/model.js +5 -0
- package/generated/api/normalize.js +231 -0
- package/generated/api/overrides-validate.js +58 -0
- package/generated/api/perf.js +12 -0
- package/generated/api/registry.js +136 -0
- package/generated/api/release.js +44 -0
- package/generated/api/resolver.js +250 -0
- package/generated/api/sources/aux-types-diff.js +75 -0
- package/generated/api/sources/client-tracker.js +11 -0
- package/generated/api/sources/creator-docs.js +42 -0
- package/generated/api/sources/luau-types.js +34 -0
- package/generated/api/sources/mini-dump.js +17 -0
- package/generated/api/sources/studio-api.js +8 -0
- package/generated/api/sources/studio-apiv2.js +11 -0
- package/generated/api/sources/studio-full-api.js +8 -0
- package/generated/api/studio-smoke.js +80 -0
- package/generated/api/type-parse.js +49 -0
- package/generated/api/understander.js +51 -0
- package/generated/api/validate.js +135 -0
- package/generated/api-cli.js +421 -0
- package/generated/cli.js +17 -6
- package/generated/clpp/contract.js +3 -3
- package/generated/clpp/format-luau.js +236 -0
- package/generated/clpp/index.js +13 -1
- package/generated/clpp/modules.js +227 -0
- package/generated/clpp/postprocess.js +86 -5
- package/generated/clpp/rewrite-janitor.js +145 -0
- package/generated/clpp/runner.js +14 -2
- package/generated/compile.js +82 -0
- package/generated/flare/index.js +15 -3
- package/generated/flare/language.js +561 -0
- package/generated/flare/parse.js +19 -7
- package/generated/intellisense.js +76 -2
- package/generated/lsp.js +118 -7
- package/generated/native/index.js +217 -16
- package/generated/target/authority-check.js +136 -0
- package/generated/target/authority-graph.js +74 -0
- package/generated/target/build-cache.js +112 -0
- package/generated/target/capabilities.js +89 -0
- package/generated/target/capability-profile.js +30 -0
- package/generated/target/component-contracts.js +60 -0
- package/generated/target/context-check.js +160 -0
- package/generated/target/datamodel-check.js +170 -0
- package/generated/target/datamodel-generate.js +74 -0
- package/generated/target/datamodel.js +233 -0
- package/generated/target/diagnostics.js +63 -0
- package/generated/target/doctor.js +152 -0
- package/generated/target/flare-version.js +58 -0
- package/generated/target/get-service.js +69 -0
- package/generated/target/lifetime-check.js +47 -0
- package/generated/target/luau-stamp.js +39 -0
- package/generated/target/optimizer-advise.js +88 -0
- package/generated/target/optimizer-apply.js +44 -0
- package/generated/target/optimizer-soa.js +254 -0
- package/generated/target/parallel-check.js +136 -0
- package/generated/target/pgo.js +148 -0
- package/generated/target/project-docs.js +69 -0
- package/generated/target/project-graph.js +71 -0
- package/generated/target/roblox.js +63 -0
- package/generated/target/security-check.js +41 -0
- package/generated/target/source-map.js +25 -0
- package/generated/target/studio-bridge.js +112 -0
- package/generated/utils/project.js +178 -8
- package/generated/utils/rojo-mapper.js +11 -3
- package/include/clpp/datatypes.clh +337 -373
- package/include/clpp/generated/enums.clh +1 -1
- package/include/clpp/generated/instances.clh +41135 -41064
- package/include/clpp/libs/axiom.clh +1 -1
- package/include/clpp/libs/hive.clh +1 -0
- package/include/clpp/libs/keep.clh +2 -0
- package/include/clpp/libs/math.clh +14 -0
- package/include/clpp/libs/roster.clh +6 -0
- package/include/clpp/libs/spring.clh +17 -0
- package/include/clpp/libs/ward.clh +1 -0
- package/include/clpp/roblox.clh +3 -4
- package/package.json +10 -3
- package/plugins/CluauppNav/Plugin.luau +207 -0
- package/plugins/CluauppNav/ProfileLogger.luau +27 -0
- package/plugins/CluauppNav/README.md +24 -0
- package/runtime/Axiom/init.luau +10 -7
- package/runtime/Coil/init.luau +8 -2
- package/runtime/Crest/init.luau +1 -0
- package/runtime/Flare/init.luau +2 -1
- package/runtime/Gleam/init.luau +15 -4
- package/runtime/Hive/init.luau +36 -14
- package/runtime/Pin/init.luau +5 -2
- package/runtime/Roster/init.luau +8 -0
- package/runtime/Spark/init.luau +3 -0
- package/runtime/Sweep/init.luau +2 -0
- package/runtime/Trace/init.luau +3 -0
- package/runtime/Ward/init.luau +38 -5
- package/scripts/postinstall-editor.js +17 -0
- package/skills/README.md +13 -0
- package/skills/clpp-hive-flare/SKILL.md +79 -0
- package/skills/clpp-language/SKILL.md +123 -0
- package/skills/clpp-language/compiler.md +89 -0
- package/skills/clpp-style/SKILL.md +95 -0
- package/src/api/build-profile.ts +138 -0
- package/src/api/cache.ts +45 -0
- package/src/api/coverage.ts +46 -0
- package/src/api/diff.ts +143 -0
- package/src/api/generators/clpp-headers.ts +377 -0
- package/src/api/generators/docs-reference.ts +11 -0
- package/src/api/generators/lsp-index.ts +106 -0
- package/src/api/generators/luau-defs.ts +98 -0
- package/src/api/ide.ts +87 -0
- package/src/api/identifier.ts +47 -0
- package/src/api/index.ts +269 -0
- package/src/api/loader.ts +60 -0
- package/src/api/merge.ts +126 -0
- package/src/api/model.ts +283 -0
- package/src/api/normalize.ts +257 -0
- package/src/api/overrides-validate.ts +58 -0
- package/src/api/perf.ts +15 -0
- package/src/api/registry.ts +162 -0
- package/src/api/release.ts +47 -0
- package/src/api/resolver.ts +255 -0
- package/src/api/sources/aux-types-diff.ts +81 -0
- package/src/api/sources/client-tracker.ts +10 -0
- package/src/api/sources/creator-docs.ts +37 -0
- package/src/api/sources/luau-types.ts +30 -0
- package/src/api/sources/mini-dump.ts +50 -0
- package/src/api/sources/studio-api.ts +7 -0
- package/src/api/sources/studio-apiv2.ts +10 -0
- package/src/api/sources/studio-full-api.ts +7 -0
- package/src/api/studio-smoke.ts +82 -0
- package/src/api/type-parse.ts +48 -0
- package/src/api/understander.ts +72 -0
- package/src/api/validate.ts +160 -0
- package/src/api-cli.ts +493 -0
- package/src/api.generated.js +37 -22
- package/src/cli.ts +22 -7
- package/src/clpp/contract.ts +34 -3
- package/src/clpp/format-luau.ts +262 -0
- package/src/clpp/index.ts +13 -2
- package/src/clpp/modules.ts +252 -0
- package/src/clpp/postprocess.ts +100 -5
- package/src/clpp/rewrite-janitor.ts +156 -0
- package/src/clpp/runner.ts +14 -2
- package/src/compile.ts +87 -0
- package/src/flare/index.ts +20 -1
- package/src/flare/language.ts +708 -0
- package/src/flare/parse.ts +20 -7
- package/src/flare/types.ts +2 -0
- package/src/intellisense.ts +76 -2
- package/src/lsp.ts +151 -8
- package/src/native/index.ts +225 -16
- package/src/target/authority-check.ts +162 -0
- package/src/target/authority-graph.ts +80 -0
- package/src/target/build-cache.ts +129 -0
- package/src/target/capabilities.ts +115 -0
- package/src/target/capability-profile.ts +25 -0
- package/src/target/component-contracts.ts +64 -0
- package/src/target/context-check.ts +177 -0
- package/src/target/datamodel-check.ts +188 -0
- package/src/target/datamodel-generate.ts +78 -0
- package/src/target/datamodel.ts +261 -0
- package/src/target/diagnostics.ts +67 -0
- package/src/target/doctor.ts +171 -0
- package/src/target/flare-version.ts +61 -0
- package/src/target/get-service.ts +85 -0
- package/src/target/lifetime-check.ts +45 -0
- package/src/target/luau-stamp.ts +33 -0
- package/src/target/optimizer-advise.ts +93 -0
- package/src/target/optimizer-apply.ts +63 -0
- package/src/target/optimizer-soa.ts +270 -0
- package/src/target/parallel-check.ts +135 -0
- package/src/target/pgo.ts +157 -0
- package/src/target/project-docs.ts +68 -0
- package/src/target/project-graph.ts +75 -0
- package/src/target/roblox.ts +78 -0
- package/src/target/security-check.ts +40 -0
- package/src/target/source-map.ts +36 -0
- package/src/target/studio-bridge.ts +140 -0
- package/src/types.ts +14 -0
- package/src/utils/project.ts +183 -9
- package/src/utils/rojo-mapper.ts +12 -3
- package/stylua.toml +9 -0
- package/templates/game/.vscode/extensions.json +3 -1
- package/templates/game/.vscode/settings.json +8 -1
- package/templates/game/include/clpp/datatypes.clh +337 -373
- package/templates/game/include/clpp/generated/enums.clh +1 -1
- package/templates/game/include/clpp/generated/instances.clh +41135 -41064
- package/templates/game/include/clpp/libs/axiom.clh +1 -1
- package/templates/game/include/clpp/libs/roster.clh +6 -0
- package/templates/game/include/clpp/libs/ward.clh +1 -0
- package/templates/game/include/clpp/roblox.clh +3 -4
- package/templates/game/src/ReplicatedStorage/Shared/Net/Net.flare +5 -0
- package/templates/game/src/ServerScriptService/Boot/DataBoot.server.clpp +2 -2
- package/templates/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
- package/templates/game/stylua.toml +9 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
--!native
|
|
2
|
+
--!optimize 2
|
|
3
|
+
--!strict
|
|
4
|
+
-- Mint — Cluaupp number display. Schema .mint bakes formatters; this kernel is the fallback.
|
|
5
|
+
-- Codegen (compileMint): Mint.Compact(value, { Fraction, Suffixes = { {threshold, label} } }),
|
|
6
|
+
-- Mint.Percent(value, fraction), Mint.Group(value, fraction). Do not rename those.
|
|
7
|
+
|
|
8
|
+
local Mint = {}
|
|
9
|
+
|
|
10
|
+
local DEFAULT_SUFFIXES = {
|
|
11
|
+
"K",
|
|
12
|
+
"M",
|
|
13
|
+
"B",
|
|
14
|
+
"T",
|
|
15
|
+
"Qa",
|
|
16
|
+
"Qi",
|
|
17
|
+
"Sx",
|
|
18
|
+
"Sp",
|
|
19
|
+
"Oc",
|
|
20
|
+
"No",
|
|
21
|
+
"Dc",
|
|
22
|
+
"Ud",
|
|
23
|
+
"Dd",
|
|
24
|
+
"Td",
|
|
25
|
+
"Qad",
|
|
26
|
+
"Qid",
|
|
27
|
+
"Sxd",
|
|
28
|
+
"Spd",
|
|
29
|
+
"Ocd",
|
|
30
|
+
"Nod",
|
|
31
|
+
"Vg",
|
|
32
|
+
"Uvg",
|
|
33
|
+
"Dvg",
|
|
34
|
+
"Tvg",
|
|
35
|
+
"Qavg",
|
|
36
|
+
"Qivg",
|
|
37
|
+
"Sxvg",
|
|
38
|
+
"Spvg",
|
|
39
|
+
"Ocvg",
|
|
40
|
+
"Novg",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type SuffixPair = { number | string }
|
|
44
|
+
export type SuffixList = { SuffixPair }
|
|
45
|
+
export type CompactOptions = { Fraction: number?, Suffixes: SuffixList? }
|
|
46
|
+
|
|
47
|
+
local function isFinite(value: number): boolean
|
|
48
|
+
return value == value and value ~= math.huge and value ~= -math.huge
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
local function special(value: number): string?
|
|
52
|
+
if value == value then
|
|
53
|
+
if value == math.huge then
|
|
54
|
+
return "∞"
|
|
55
|
+
end
|
|
56
|
+
if value == -math.huge then
|
|
57
|
+
return "-∞"
|
|
58
|
+
end
|
|
59
|
+
return nil
|
|
60
|
+
end
|
|
61
|
+
return "NaN"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
local function group(digits: string): string
|
|
65
|
+
local sign = ""
|
|
66
|
+
if string.sub(digits, 1, 1) == "-" then
|
|
67
|
+
sign = "-"
|
|
68
|
+
digits = string.sub(digits, 2)
|
|
69
|
+
end
|
|
70
|
+
local whole, frac = string.match(digits, "^(%d+)(%.%d+)$")
|
|
71
|
+
if not whole then
|
|
72
|
+
whole = digits
|
|
73
|
+
frac = ""
|
|
74
|
+
end
|
|
75
|
+
local built = {}
|
|
76
|
+
local n = #whole
|
|
77
|
+
local start = n % 3
|
|
78
|
+
if start == 0 then
|
|
79
|
+
start = 3
|
|
80
|
+
end
|
|
81
|
+
table.insert(built, string.sub(whole, 1, start))
|
|
82
|
+
for i = start + 1, n, 3 do
|
|
83
|
+
table.insert(built, string.sub(whole, i, i + 2))
|
|
84
|
+
end
|
|
85
|
+
return sign .. table.concat(built, ",") .. frac
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
local function trimFraction(value: number, places: number): string
|
|
89
|
+
if not isFinite(value) then
|
|
90
|
+
return special(value) :: string
|
|
91
|
+
end
|
|
92
|
+
if places <= 0 then
|
|
93
|
+
return tostring(math.floor(value + (if value >= 0 then 0.5 else -0.5)))
|
|
94
|
+
end
|
|
95
|
+
local m = 10 ^ places
|
|
96
|
+
local rounded = math.floor(value * m + (if value >= 0 then 0.5 else -0.5)) / m
|
|
97
|
+
local text = string.format("%." .. places .. "f", rounded)
|
|
98
|
+
text = string.gsub(text, "%.?0+$", "")
|
|
99
|
+
return text
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
function Mint.Suffixes(labels: { string }): SuffixList
|
|
103
|
+
local baked: SuffixList = {}
|
|
104
|
+
for i, label in labels do
|
|
105
|
+
table.insert(baked, { 10 ^ (i * 3), label })
|
|
106
|
+
end
|
|
107
|
+
return baked
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
local function defaultSuffixes(): SuffixList
|
|
111
|
+
return Mint.Suffixes(DEFAULT_SUFFIXES)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
local function asSuffixList(suffixes: SuffixList?): SuffixList
|
|
115
|
+
if suffixes == nil then
|
|
116
|
+
return defaultSuffixes()
|
|
117
|
+
end
|
|
118
|
+
if #suffixes == 0 then
|
|
119
|
+
return suffixes
|
|
120
|
+
end
|
|
121
|
+
if type(suffixes[1]) == "string" then
|
|
122
|
+
return Mint.Suffixes(suffixes :: any)
|
|
123
|
+
end
|
|
124
|
+
return suffixes
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
function Mint.Group(value: number, fraction: number?): string
|
|
128
|
+
local text = special(value)
|
|
129
|
+
if text then
|
|
130
|
+
return text
|
|
131
|
+
end
|
|
132
|
+
local places = fraction or 0
|
|
133
|
+
return group(trimFraction(value, places))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
function Mint.Comma(value: number): string
|
|
137
|
+
return Mint.Group(value, 0)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
function Mint.Compact(value: number, options: (CompactOptions | number)?): string
|
|
141
|
+
local text = special(value)
|
|
142
|
+
if text then
|
|
143
|
+
return text
|
|
144
|
+
end
|
|
145
|
+
local sign = if value < 0 then "-" else ""
|
|
146
|
+
local n = math.abs(value)
|
|
147
|
+
local fraction = 1
|
|
148
|
+
local suffixInput: SuffixList? = nil
|
|
149
|
+
if type(options) == "number" then
|
|
150
|
+
fraction = options
|
|
151
|
+
elseif type(options) == "table" then
|
|
152
|
+
fraction = (options :: CompactOptions).Fraction or 1
|
|
153
|
+
suffixInput = (options :: CompactOptions).Suffixes
|
|
154
|
+
end
|
|
155
|
+
local suffixes = asSuffixList(suffixInput)
|
|
156
|
+
local chosen: SuffixPair? = nil
|
|
157
|
+
local best = 0
|
|
158
|
+
for i = 1, #suffixes do
|
|
159
|
+
local threshold = suffixes[i][1] :: number
|
|
160
|
+
if threshold > 0 and n >= threshold and threshold >= best then
|
|
161
|
+
best = threshold
|
|
162
|
+
chosen = suffixes[i]
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
if not chosen then
|
|
166
|
+
return sign .. trimFraction(n, fraction)
|
|
167
|
+
end
|
|
168
|
+
local scaled = n / (chosen[1] :: number)
|
|
169
|
+
local places = 10 ^ fraction
|
|
170
|
+
scaled = math.floor(scaled * places) / places
|
|
171
|
+
return sign .. trimFraction(scaled, fraction) .. (chosen[2] :: string)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
function Mint.Abbreviate(value: number, digits: number?): string
|
|
175
|
+
return Mint.Compact(value, { Fraction = digits or 1 })
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
function Mint.Percent(value: number, fraction: number?): string
|
|
179
|
+
local text = special(value)
|
|
180
|
+
if text then
|
|
181
|
+
return text
|
|
182
|
+
end
|
|
183
|
+
return trimFraction(value * 100, fraction or 1) .. "%"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
function Mint.Scientific(value: number, fraction: number?): string
|
|
187
|
+
local text = special(value)
|
|
188
|
+
if text then
|
|
189
|
+
return text
|
|
190
|
+
end
|
|
191
|
+
local places = fraction or 1
|
|
192
|
+
if value == 0 then
|
|
193
|
+
return "0e+0"
|
|
194
|
+
end
|
|
195
|
+
local sign = if value < 0 then "-" else ""
|
|
196
|
+
local n = math.abs(value)
|
|
197
|
+
local exp = math.floor(math.log(n, 10))
|
|
198
|
+
local mantissa = n / (10 ^ exp)
|
|
199
|
+
if places <= 0 then
|
|
200
|
+
mantissa = math.floor(mantissa + 0.5)
|
|
201
|
+
else
|
|
202
|
+
local m = 10 ^ places
|
|
203
|
+
mantissa = math.floor(mantissa * m + 0.5) / m
|
|
204
|
+
end
|
|
205
|
+
if mantissa >= 10 then
|
|
206
|
+
mantissa /= 10
|
|
207
|
+
exp += 1
|
|
208
|
+
end
|
|
209
|
+
local expSign = if exp >= 0 then "+" else ""
|
|
210
|
+
return sign .. trimFraction(mantissa, places) .. "e" .. expSign .. tostring(exp)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
function Mint.To(value: number, fraction: number?): string
|
|
214
|
+
return Mint.Group(value, fraction)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
local function suffixFactor(label: string, suffixes: SuffixList): number?
|
|
218
|
+
if label == "" then
|
|
219
|
+
return nil
|
|
220
|
+
end
|
|
221
|
+
local lower = string.lower(label)
|
|
222
|
+
for i = #suffixes, 1, -1 do
|
|
223
|
+
local pair = suffixes[i]
|
|
224
|
+
local name = pair[2] :: string
|
|
225
|
+
if name and string.lower(name) == lower then
|
|
226
|
+
return pair[1] :: number
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
return nil
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
function Mint.From(text: string, suffixes: SuffixList?): number
|
|
233
|
+
local trimmed = string.gsub(string.gsub(text, "^%s+", ""), "%s+$", "")
|
|
234
|
+
if trimmed == "" then
|
|
235
|
+
return 0 / 0
|
|
236
|
+
end
|
|
237
|
+
if trimmed == "NaN" or trimmed == "nan" then
|
|
238
|
+
return 0 / 0
|
|
239
|
+
end
|
|
240
|
+
if trimmed == "∞" or trimmed == "inf" or trimmed == "Inf" or trimmed == "Infinity" then
|
|
241
|
+
return math.huge
|
|
242
|
+
end
|
|
243
|
+
if trimmed == "-∞" or trimmed == "-inf" or trimmed == "-Inf" or trimmed == "-Infinity" then
|
|
244
|
+
return -math.huge
|
|
245
|
+
end
|
|
246
|
+
local percent = false
|
|
247
|
+
if string.sub(trimmed, -1) == "%" then
|
|
248
|
+
percent = true
|
|
249
|
+
trimmed = string.sub(trimmed, 1, -2)
|
|
250
|
+
end
|
|
251
|
+
local stripped = string.gsub(trimmed, ",", "")
|
|
252
|
+
local numberPart, suffixPart = string.match(stripped, "^([%+%-]?%d*%.?%d+[eE][%+%-]?%d+)(.*)$")
|
|
253
|
+
if not numberPart then
|
|
254
|
+
numberPart, suffixPart = string.match(stripped, "^([%+%-]?%d*%.?%d+)(.*)$")
|
|
255
|
+
end
|
|
256
|
+
if not numberPart then
|
|
257
|
+
return 0 / 0
|
|
258
|
+
end
|
|
259
|
+
local n = tonumber(numberPart)
|
|
260
|
+
if not n then
|
|
261
|
+
return 0 / 0
|
|
262
|
+
end
|
|
263
|
+
suffixPart = string.gsub(suffixPart or "", "%s+", "")
|
|
264
|
+
if suffixPart ~= "" then
|
|
265
|
+
local factor = suffixFactor(suffixPart, asSuffixList(suffixes))
|
|
266
|
+
if not factor then
|
|
267
|
+
return 0 / 0
|
|
268
|
+
end
|
|
269
|
+
n *= factor
|
|
270
|
+
end
|
|
271
|
+
if percent then
|
|
272
|
+
n /= 100
|
|
273
|
+
end
|
|
274
|
+
return n
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
Mint.Format = Mint.Group
|
|
278
|
+
|
|
279
|
+
return Mint
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
@class Net
|
|
4
|
+
Buffer-packed RemoteEvent / RemoteFunction. Public API is generic; the codec is internal.
|
|
5
|
+
]=]
|
|
6
|
+
local RunService = game:GetService("RunService")
|
|
7
|
+
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
8
|
+
local codec = require(script.src.codec)
|
|
9
|
+
local Ward = require(script.Parent.Ward)
|
|
10
|
+
|
|
11
|
+
export type Event<T...> = {
|
|
12
|
+
Fire: (self: Event<T...>, player: Player, T...) -> (),
|
|
13
|
+
FireAll: (self: Event<T...>, T...) -> (),
|
|
14
|
+
FireServer: (self: Event<T...>, T...) -> (),
|
|
15
|
+
On: (self: Event<T...>, callback: (Player?, T...) -> ()) -> RBXScriptConnection,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type Function<R, T...> = {
|
|
19
|
+
On: (self: Function<R, T...>, callback: (Player?, T...) -> R) -> (),
|
|
20
|
+
Invoke: (self: Function<R, T...>, player: Player, T...) -> R,
|
|
21
|
+
InvokeServer: (self: Function<R, T...>, T...) -> R,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
local function folder(): Folder
|
|
25
|
+
local existing = ReplicatedStorage:FindFirstChild("CluauppNet")
|
|
26
|
+
if existing and existing:IsA("Folder") then
|
|
27
|
+
return existing
|
|
28
|
+
end
|
|
29
|
+
local created = Instance.new("Folder")
|
|
30
|
+
created.Name = "CluauppNet"
|
|
31
|
+
created.Parent = ReplicatedStorage
|
|
32
|
+
return created
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
local function remote(kind: "RemoteEvent" | "RemoteFunction", name: string): Instance
|
|
36
|
+
local parent = folder()
|
|
37
|
+
local existing = parent:FindFirstChild(name)
|
|
38
|
+
if existing then
|
|
39
|
+
return existing
|
|
40
|
+
end
|
|
41
|
+
if RunService:IsServer() then
|
|
42
|
+
local inst = Instance.new(kind)
|
|
43
|
+
inst.Name = name
|
|
44
|
+
inst.Parent = parent
|
|
45
|
+
return inst
|
|
46
|
+
end
|
|
47
|
+
return parent:WaitForChild(name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
local Event = {}
|
|
51
|
+
Event.__index = Event
|
|
52
|
+
|
|
53
|
+
function Event.new<T...>(name: string): Event<T...>
|
|
54
|
+
return setmetatable({ _name = name, _remote = remote("RemoteEvent", name) :: RemoteEvent }, Event) :: Event<T...>
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
function Event:Fire<T...>(player: Player, ...: T...)
|
|
58
|
+
assert(RunService:IsServer(), "Net.Event:Fire is server-only")
|
|
59
|
+
self._remote:FireClient(player, codec.encode({ ... }))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
function Event:FireAll<T...>(...: T...)
|
|
63
|
+
assert(RunService:IsServer(), "Net.Event:FireAll is server-only")
|
|
64
|
+
self._remote:FireAllClients(codec.encode({ ... }))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
function Event:FireServer<T...>(...: T...)
|
|
68
|
+
assert(RunService:IsClient(), "Net.Event:FireServer is client-only")
|
|
69
|
+
self._remote:FireServer(codec.encode({ ... }))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
function Event:On<T...>(callback: (Player?, T...) -> ()): RBXScriptConnection
|
|
73
|
+
if RunService:IsServer() then
|
|
74
|
+
return self._remote.OnServerEvent:Connect(function(player: Player, payload: buffer)
|
|
75
|
+
if typeof(payload) ~= "buffer" then
|
|
76
|
+
Ward.Strike(player, "net:type")
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
if not Ward.Packet(player, buffer.len(payload)) then
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
if not Ward.Allow(player, "net:" .. self._name, 30, 60) then
|
|
83
|
+
return
|
|
84
|
+
end
|
|
85
|
+
local ok, decoded = pcall(codec.decode, payload)
|
|
86
|
+
if not ok or typeof(decoded) ~= "table" then
|
|
87
|
+
Ward.Strike(player, "net:decode")
|
|
88
|
+
return
|
|
89
|
+
end
|
|
90
|
+
callback(player, table.unpack(decoded))
|
|
91
|
+
end)
|
|
92
|
+
end
|
|
93
|
+
return self._remote.OnClientEvent:Connect(function(payload: buffer)
|
|
94
|
+
callback(nil, table.unpack(codec.decode(payload)))
|
|
95
|
+
end)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
local Fn = {}
|
|
99
|
+
Fn.__index = Fn
|
|
100
|
+
|
|
101
|
+
function Fn.new<R, T...>(name: string): Function<R, T...>
|
|
102
|
+
return setmetatable({ _name = name, _remote = remote("RemoteFunction", name) :: RemoteFunction }, Fn) :: Function<R, T...>
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
function Fn:On<R, T...>(callback: (Player?, T...) -> R)
|
|
106
|
+
if RunService:IsServer() then
|
|
107
|
+
self._remote.OnServerInvoke = function(player: Player, payload: buffer)
|
|
108
|
+
if typeof(payload) ~= "buffer" then
|
|
109
|
+
Ward.Strike(player, "net:fn-type")
|
|
110
|
+
return codec.encode({})
|
|
111
|
+
end
|
|
112
|
+
if not Ward.Packet(player, buffer.len(payload)) then
|
|
113
|
+
return codec.encode({})
|
|
114
|
+
end
|
|
115
|
+
if not Ward.Allow(player, "netfn:" .. self._name, 10, 20) then
|
|
116
|
+
return codec.encode({})
|
|
117
|
+
end
|
|
118
|
+
local ok, decoded = pcall(codec.decode, payload)
|
|
119
|
+
if not ok or typeof(decoded) ~= "table" then
|
|
120
|
+
Ward.Strike(player, "net:fn-decode")
|
|
121
|
+
return codec.encode({})
|
|
122
|
+
end
|
|
123
|
+
return codec.encode({ callback(player, table.unpack(decoded)) })
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
self._remote.OnClientInvoke = function(payload: buffer)
|
|
127
|
+
return codec.encode({ callback(nil, table.unpack(codec.decode(payload))) })
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
function Fn:Invoke<R, T...>(player: Player, ...: T...): R
|
|
133
|
+
assert(RunService:IsServer(), "Net.Function:Invoke is server-only")
|
|
134
|
+
local reply = self._remote:InvokeClient(player, codec.encode({ ... }))
|
|
135
|
+
return table.unpack(codec.decode(reply)) :: R
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
function Fn:InvokeServer<R, T...>(...: T...): R
|
|
139
|
+
assert(RunService:IsClient(), "Net.Function:InvokeServer is client-only")
|
|
140
|
+
local reply = self._remote:InvokeServer(codec.encode({ ... }))
|
|
141
|
+
return table.unpack(codec.decode(reply)) :: R
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
local Net = {}
|
|
145
|
+
|
|
146
|
+
function Net.Event<T...>(name: string): Event<T...>
|
|
147
|
+
return Event.new(name)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
function Net.Function<R, T...>(name: string): Function<R, T...>
|
|
151
|
+
return Fn.new(name)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
export type Net = typeof(Net)
|
|
155
|
+
|
|
156
|
+
return Net
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
--!nonstrict
|
|
2
|
+
-- Buffer codec for Net. Tagged values — never JSON on the hot path.
|
|
3
|
+
|
|
4
|
+
local Players = game:GetService("Players")
|
|
5
|
+
|
|
6
|
+
local TAG_NIL = 0
|
|
7
|
+
local TAG_BOOL = 1
|
|
8
|
+
local TAG_NUM = 2
|
|
9
|
+
local TAG_STR = 3
|
|
10
|
+
local TAG_V3 = 4
|
|
11
|
+
local TAG_CF = 5
|
|
12
|
+
local TAG_COL = 6
|
|
13
|
+
local TAG_PLAYER = 7
|
|
14
|
+
local TAG_TABLE = 8
|
|
15
|
+
local TAG_V2 = 9
|
|
16
|
+
local TAG_UDIM = 10
|
|
17
|
+
local TAG_UDIM2 = 11
|
|
18
|
+
|
|
19
|
+
local MAX_DEPTH = 16
|
|
20
|
+
|
|
21
|
+
local estimate: (any, number) -> number
|
|
22
|
+
local writeValue: (buffer, number, any, number) -> number
|
|
23
|
+
local readValue: (buffer, number) -> (any, number)
|
|
24
|
+
|
|
25
|
+
estimate = function(value, depth: number): number
|
|
26
|
+
if depth > MAX_DEPTH then
|
|
27
|
+
return 1
|
|
28
|
+
end
|
|
29
|
+
local kind = typeof(value)
|
|
30
|
+
if value == nil then
|
|
31
|
+
return 1
|
|
32
|
+
elseif kind == "boolean" then
|
|
33
|
+
return 2
|
|
34
|
+
elseif kind == "number" then
|
|
35
|
+
return 9
|
|
36
|
+
elseif kind == "string" then
|
|
37
|
+
return 5 + #value
|
|
38
|
+
elseif kind == "Vector3" then
|
|
39
|
+
return 25
|
|
40
|
+
elseif kind == "Vector2" then
|
|
41
|
+
return 17
|
|
42
|
+
elseif kind == "CFrame" then
|
|
43
|
+
return 1 + 96
|
|
44
|
+
elseif kind == "Color3" then
|
|
45
|
+
return 25
|
|
46
|
+
elseif kind == "UDim" then
|
|
47
|
+
return 13
|
|
48
|
+
elseif kind == "UDim2" then
|
|
49
|
+
return 25
|
|
50
|
+
elseif kind == "Instance" and value:IsA("Player") then
|
|
51
|
+
return 9
|
|
52
|
+
elseif kind == "table" then
|
|
53
|
+
local size = 5
|
|
54
|
+
for key, child in value do
|
|
55
|
+
size += estimate(key, depth + 1) + estimate(child, depth + 1)
|
|
56
|
+
end
|
|
57
|
+
return size
|
|
58
|
+
end
|
|
59
|
+
return 1
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
writeValue = function(buf: buffer, offset: number, value, depth: number): number
|
|
63
|
+
if depth > MAX_DEPTH then
|
|
64
|
+
buffer.writeu8(buf, offset, TAG_NIL)
|
|
65
|
+
return offset + 1
|
|
66
|
+
end
|
|
67
|
+
local kind = typeof(value)
|
|
68
|
+
if value == nil then
|
|
69
|
+
buffer.writeu8(buf, offset, TAG_NIL)
|
|
70
|
+
return offset + 1
|
|
71
|
+
elseif kind == "boolean" then
|
|
72
|
+
buffer.writeu8(buf, offset, TAG_BOOL)
|
|
73
|
+
buffer.writeu8(buf, offset + 1, if value then 1 else 0)
|
|
74
|
+
return offset + 2
|
|
75
|
+
elseif kind == "number" then
|
|
76
|
+
buffer.writeu8(buf, offset, TAG_NUM)
|
|
77
|
+
buffer.writef64(buf, offset + 1, value)
|
|
78
|
+
return offset + 9
|
|
79
|
+
elseif kind == "string" then
|
|
80
|
+
buffer.writeu8(buf, offset, TAG_STR)
|
|
81
|
+
buffer.writeu32(buf, offset + 1, #value)
|
|
82
|
+
buffer.writestring(buf, offset + 5, value)
|
|
83
|
+
return offset + 5 + #value
|
|
84
|
+
elseif kind == "Vector3" then
|
|
85
|
+
buffer.writeu8(buf, offset, TAG_V3)
|
|
86
|
+
buffer.writef64(buf, offset + 1, value.X)
|
|
87
|
+
buffer.writef64(buf, offset + 9, value.Y)
|
|
88
|
+
buffer.writef64(buf, offset + 17, value.Z)
|
|
89
|
+
return offset + 25
|
|
90
|
+
elseif kind == "Vector2" then
|
|
91
|
+
buffer.writeu8(buf, offset, TAG_V2)
|
|
92
|
+
buffer.writef64(buf, offset + 1, value.X)
|
|
93
|
+
buffer.writef64(buf, offset + 9, value.Y)
|
|
94
|
+
return offset + 17
|
|
95
|
+
elseif kind == "CFrame" then
|
|
96
|
+
buffer.writeu8(buf, offset, TAG_CF)
|
|
97
|
+
local components = { value:GetComponents() }
|
|
98
|
+
for i = 1, 12 do
|
|
99
|
+
buffer.writef64(buf, offset + 1 + (i - 1) * 8, components[i])
|
|
100
|
+
end
|
|
101
|
+
return offset + 1 + 96
|
|
102
|
+
elseif kind == "Color3" then
|
|
103
|
+
buffer.writeu8(buf, offset, TAG_COL)
|
|
104
|
+
buffer.writef64(buf, offset + 1, value.R)
|
|
105
|
+
buffer.writef64(buf, offset + 9, value.G)
|
|
106
|
+
buffer.writef64(buf, offset + 17, value.B)
|
|
107
|
+
return offset + 25
|
|
108
|
+
elseif kind == "UDim" then
|
|
109
|
+
buffer.writeu8(buf, offset, TAG_UDIM)
|
|
110
|
+
buffer.writef32(buf, offset + 1, value.Scale)
|
|
111
|
+
buffer.writei32(buf, offset + 5, value.Offset)
|
|
112
|
+
return offset + 13
|
|
113
|
+
elseif kind == "UDim2" then
|
|
114
|
+
buffer.writeu8(buf, offset, TAG_UDIM2)
|
|
115
|
+
buffer.writef32(buf, offset + 1, value.X.Scale)
|
|
116
|
+
buffer.writei32(buf, offset + 5, value.X.Offset)
|
|
117
|
+
buffer.writef32(buf, offset + 9, value.Y.Scale)
|
|
118
|
+
buffer.writei32(buf, offset + 13, value.Y.Offset)
|
|
119
|
+
return offset + 17
|
|
120
|
+
elseif kind == "Instance" and value:IsA("Player") then
|
|
121
|
+
buffer.writeu8(buf, offset, TAG_PLAYER)
|
|
122
|
+
buffer.writef64(buf, offset + 1, value.UserId)
|
|
123
|
+
return offset + 9
|
|
124
|
+
elseif kind == "table" then
|
|
125
|
+
local count = 0
|
|
126
|
+
for _ in value do
|
|
127
|
+
count += 1
|
|
128
|
+
end
|
|
129
|
+
buffer.writeu8(buf, offset, TAG_TABLE)
|
|
130
|
+
buffer.writeu32(buf, offset + 1, count)
|
|
131
|
+
offset += 5
|
|
132
|
+
for key, child in value do
|
|
133
|
+
offset = writeValue(buf, offset, key, depth + 1)
|
|
134
|
+
offset = writeValue(buf, offset, child, depth + 1)
|
|
135
|
+
end
|
|
136
|
+
return offset
|
|
137
|
+
end
|
|
138
|
+
buffer.writeu8(buf, offset, TAG_NIL)
|
|
139
|
+
return offset + 1
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
local function encode(values): buffer
|
|
143
|
+
local size = 1
|
|
144
|
+
for _, value in values do
|
|
145
|
+
size += estimate(value, 0)
|
|
146
|
+
end
|
|
147
|
+
local buf = buffer.create(size)
|
|
148
|
+
buffer.writeu8(buf, 0, #values)
|
|
149
|
+
local offset = 1
|
|
150
|
+
for _, value in values do
|
|
151
|
+
offset = writeValue(buf, offset, value, 0)
|
|
152
|
+
end
|
|
153
|
+
return buf
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
readValue = function(buf: buffer, offset: number)
|
|
157
|
+
local tag = buffer.readu8(buf, offset)
|
|
158
|
+
offset += 1
|
|
159
|
+
if tag == TAG_NIL then
|
|
160
|
+
return nil, offset
|
|
161
|
+
elseif tag == TAG_BOOL then
|
|
162
|
+
return buffer.readu8(buf, offset) == 1, offset + 1
|
|
163
|
+
elseif tag == TAG_NUM then
|
|
164
|
+
return buffer.readf64(buf, offset), offset + 8
|
|
165
|
+
elseif tag == TAG_STR then
|
|
166
|
+
local len = buffer.readu32(buf, offset)
|
|
167
|
+
return buffer.readstring(buf, offset + 4, len), offset + 4 + len
|
|
168
|
+
elseif tag == TAG_V3 then
|
|
169
|
+
return Vector3.new(buffer.readf64(buf, offset), buffer.readf64(buf, offset + 8), buffer.readf64(buf, offset + 16)), offset + 24
|
|
170
|
+
elseif tag == TAG_V2 then
|
|
171
|
+
return Vector2.new(buffer.readf64(buf, offset), buffer.readf64(buf, offset + 8)), offset + 16
|
|
172
|
+
elseif tag == TAG_CF then
|
|
173
|
+
local c = table.create(12)
|
|
174
|
+
for i = 1, 12 do
|
|
175
|
+
c[i] = buffer.readf64(buf, offset + (i - 1) * 8)
|
|
176
|
+
end
|
|
177
|
+
return CFrame.new(table.unpack(c)), offset + 96
|
|
178
|
+
elseif tag == TAG_COL then
|
|
179
|
+
return Color3.new(buffer.readf64(buf, offset), buffer.readf64(buf, offset + 8), buffer.readf64(buf, offset + 16)), offset + 24
|
|
180
|
+
elseif tag == TAG_UDIM then
|
|
181
|
+
return UDim.new(buffer.readf32(buf, offset), buffer.readi32(buf, offset + 4)), offset + 12
|
|
182
|
+
elseif tag == TAG_UDIM2 then
|
|
183
|
+
return UDim2.new(
|
|
184
|
+
buffer.readf32(buf, offset),
|
|
185
|
+
buffer.readi32(buf, offset + 4),
|
|
186
|
+
buffer.readf32(buf, offset + 8),
|
|
187
|
+
buffer.readi32(buf, offset + 12)
|
|
188
|
+
),
|
|
189
|
+
offset + 16
|
|
190
|
+
elseif tag == TAG_PLAYER then
|
|
191
|
+
local userId = buffer.readf64(buf, offset)
|
|
192
|
+
return Players:GetPlayerByUserId(userId), offset + 8
|
|
193
|
+
elseif tag == TAG_TABLE then
|
|
194
|
+
local count = buffer.readu32(buf, offset)
|
|
195
|
+
offset += 4
|
|
196
|
+
local out = {}
|
|
197
|
+
for _ = 1, count do
|
|
198
|
+
local key
|
|
199
|
+
key, offset = readValue(buf, offset)
|
|
200
|
+
local child
|
|
201
|
+
child, offset = readValue(buf, offset)
|
|
202
|
+
out[key] = child
|
|
203
|
+
end
|
|
204
|
+
return out, offset
|
|
205
|
+
end
|
|
206
|
+
return nil, offset
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
local function decode(buf: buffer)
|
|
210
|
+
local count = buffer.readu8(buf, 0)
|
|
211
|
+
local offset = 1
|
|
212
|
+
local values = table.create(count)
|
|
213
|
+
for i = 1, count do
|
|
214
|
+
local value
|
|
215
|
+
value, offset = readValue(buf, offset)
|
|
216
|
+
values[i] = value
|
|
217
|
+
end
|
|
218
|
+
return values
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
encode = encode,
|
|
223
|
+
decode = decode,
|
|
224
|
+
}
|