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.
Files changed (340) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +10 -5
  3. package/api/CHANGELOG.md +3 -0
  4. package/api/chat.js +74 -0
  5. package/api/fixtures/roblox/README.md +6 -0
  6. package/api/fixtures/roblox/aux/sample.d.luau +6 -0
  7. package/api/fixtures/roblox/mini/Mini-API-Dump.json +72 -0
  8. package/api/generated/bench-latest.json +39 -0
  9. package/api/generated/capability-profile.json +76 -0
  10. package/api/generated/lsp-index.json +1 -0
  11. package/api/generated/luau/classes.d.luau +11221 -0
  12. package/api/generated/luau/datatypes.d.luau +327 -0
  13. package/api/generated/luau/enums.d.luau +4918 -0
  14. package/api/generated/luau/globals.d.luau +12 -0
  15. package/api/manifests/roblox-target.manifest.json +22 -0
  16. package/api/normalized/roblox-target.profile.json +237461 -0
  17. package/api/overrides/classes.json +8 -0
  18. package/api/overrides/compatibility.json +9 -0
  19. package/api/overrides/datatypes.json +1579 -0
  20. package/api/overrides/enums.json +8 -0
  21. package/api/overrides/globals.json +8 -0
  22. package/api/overrides/type-mappings.json +9 -0
  23. package/api/roblox-api.lock.json +9 -0
  24. package/data/Mini-API-Dump.json +1 -0
  25. package/editors/vscode/README.md +19 -0
  26. package/editors/vscode/extension.js +222 -21
  27. package/editors/vscode/icons/axiom.svg +4 -0
  28. package/editors/vscode/icons/bloom.svg +5 -0
  29. package/editors/vscode/icons/flare.svg +5 -0
  30. package/editors/vscode/icons/helm.svg +4 -0
  31. package/editors/vscode/icons/hive.svg +5 -0
  32. package/editors/vscode/icons/mint.svg +4 -0
  33. package/editors/vscode/icons/shift.svg +6 -0
  34. package/editors/vscode/language-configuration-schema.json +24 -0
  35. package/editors/vscode/language-configuration.json +21 -0
  36. package/editors/vscode/package.json +220 -6
  37. package/editors/vscode/snippets/axiom.json +12 -0
  38. package/editors/vscode/snippets/bloom.json +12 -0
  39. package/editors/vscode/snippets/flare.json +27 -0
  40. package/editors/vscode/snippets/helm.json +12 -0
  41. package/editors/vscode/snippets/hive.json +12 -0
  42. package/editors/vscode/snippets/mint.json +12 -0
  43. package/editors/vscode/snippets/shift.json +17 -0
  44. package/editors/vscode/syntaxes/axiom.tmLanguage.json +5 -0
  45. package/editors/vscode/syntaxes/bloom.tmLanguage.json +5 -0
  46. package/editors/vscode/syntaxes/flare.tmLanguage.json +75 -0
  47. package/editors/vscode/syntaxes/helm.tmLanguage.json +5 -0
  48. package/editors/vscode/syntaxes/hive.tmLanguage.json +5 -0
  49. package/editors/vscode/syntaxes/mint.tmLanguage.json +5 -0
  50. package/editors/vscode/syntaxes/schema.tmLanguage.json +89 -0
  51. package/editors/vscode/syntaxes/shift.tmLanguage.json +5 -0
  52. package/examples/game/.cluaupp/compile-cache/ReplicatedStorage__Shared__Constants__Datas__TemplateData.clh.json +1 -0
  53. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Boot__DataBoot.server.clpp.json +1 -0
  54. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Configuration__ServerConfig.clp.json +1 -0
  55. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__Guard.server.clpp.json +1 -0
  56. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__PlayerHandler.server.clpp.json +1 -0
  57. package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterCharacterScripts__Character__CharacterReady.client.clpp.json +1 -0
  58. package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterPlayerScripts__Controllers__DataController.client.clpp.json +1 -0
  59. package/examples/game/.cluaupp/compile-cache/index.json +12 -0
  60. package/examples/game/.cluaupp/datamodel-profile.json +94 -0
  61. package/examples/game/.vscode/extensions.json +3 -1
  62. package/examples/game/.vscode/settings.json +13 -1
  63. package/examples/game/include/clpp/datatypes.clh +337 -373
  64. package/examples/game/include/clpp/generated/datamodel.clh +25 -0
  65. package/examples/game/include/clpp/generated/enums.clh +1 -1
  66. package/examples/game/include/clpp/generated/instances.clh +41135 -41064
  67. package/examples/game/include/clpp/libs/axiom.clh +1 -1
  68. package/examples/game/include/clpp/libs/math.clh +14 -0
  69. package/examples/game/include/clpp/libs/roster.clh +6 -0
  70. package/examples/game/include/clpp/libs/spring.clh +17 -0
  71. package/examples/game/include/clpp/libs/ward.clh +1 -0
  72. package/examples/game/include/clpp/roblox.clh +3 -4
  73. package/examples/game/libs/ArrayIndexer/init.luau +209 -0
  74. package/examples/game/libs/Axiom/init.luau +608 -0
  75. package/examples/game/libs/Bloom/init.luau +433 -0
  76. package/examples/game/libs/Coil/init.luau +215 -0
  77. package/examples/game/libs/Crest/init.luau +426 -0
  78. package/examples/game/libs/Echo/init.luau +417 -0
  79. package/examples/game/libs/Ember/init.luau +365 -0
  80. package/examples/game/libs/Flare/init.luau +717 -0
  81. package/examples/game/libs/Gleam/init.luau +729 -0
  82. package/examples/game/libs/Guide/init.luau +215 -0
  83. package/examples/game/libs/Helm/init.luau +377 -0
  84. package/examples/game/libs/Hive/init.luau +241 -0
  85. package/examples/game/libs/Keep/Client.luau +114 -0
  86. package/examples/game/libs/Keep/Data.luau +883 -0
  87. package/examples/game/libs/Keep/Engine.luau +211 -0
  88. package/examples/game/libs/Keep/Enum.luau +6 -0
  89. package/examples/game/libs/Keep/Enums.luau +10 -0
  90. package/examples/game/libs/Keep/Path.luau +236 -0
  91. package/examples/game/libs/Keep/Replicator.luau +298 -0
  92. package/examples/game/libs/Keep/Server.luau +251 -0
  93. package/examples/game/libs/Keep/Store.luau +652 -0
  94. package/examples/game/libs/Keep/Trade.luau +455 -0
  95. package/examples/game/libs/Keep/init.luau +205 -0
  96. package/examples/game/libs/Lens/init.luau +609 -0
  97. package/examples/game/libs/Mint/init.luau +279 -0
  98. package/examples/game/libs/Net/init.luau +156 -0
  99. package/examples/game/libs/Net/src/codec.luau +224 -0
  100. package/examples/game/libs/Occlude/init.luau +117 -0
  101. package/examples/game/libs/Pin/init.luau +309 -0
  102. package/examples/game/libs/Promise/LICENSE +21 -0
  103. package/examples/game/libs/Promise/_impl/LICENSE +21 -0
  104. package/examples/game/libs/Promise/_impl/init.lua +1991 -0
  105. package/examples/game/libs/Promise/init.lua +1990 -0
  106. package/examples/game/libs/Promise/init.luau +13 -0
  107. package/examples/game/libs/Promise/types.luau +46 -0
  108. package/examples/game/libs/Roster/init.luau +686 -0
  109. package/examples/game/libs/SOURCES.md +31 -0
  110. package/examples/game/libs/Shift/init.luau +238 -0
  111. package/examples/game/libs/Spark/init.luau +487 -0
  112. package/examples/game/libs/Stage/init.luau +178 -0
  113. package/examples/game/libs/Sweep/init.luau +259 -0
  114. package/examples/game/libs/Trace/init.luau +213 -0
  115. package/examples/game/libs/Ward/init.luau +211 -0
  116. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +29 -0
  117. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +13 -0
  118. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +83 -0
  119. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +13 -0
  120. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +18 -0
  121. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +13 -0
  122. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +14 -0
  123. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +13 -0
  124. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +15 -0
  125. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +13 -0
  126. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +50 -0
  127. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +13 -0
  128. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +12 -0
  129. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +13 -0
  130. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +16 -0
  131. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +13 -0
  132. package/examples/game/src/ReplicatedStorage/Shared/Net/Net.clh +26 -0
  133. package/examples/game/src/ReplicatedStorage/Shared/Net/Net.flare +5 -0
  134. package/examples/game/src/ServerScriptService/Boot/DataBoot.server.clpp +2 -2
  135. package/examples/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
  136. package/examples/game/stylua.toml +9 -0
  137. package/generated/api/build-profile.js +115 -0
  138. package/generated/api/cache.js +44 -0
  139. package/generated/api/coverage.js +32 -0
  140. package/generated/api/diff.js +125 -0
  141. package/generated/api/generators/clpp-headers.js +353 -0
  142. package/generated/api/generators/docs-reference.js +7 -0
  143. package/generated/api/generators/lsp-index.js +81 -0
  144. package/generated/api/generators/luau-defs.js +94 -0
  145. package/generated/api/ide.js +76 -0
  146. package/generated/api/identifier.js +47 -0
  147. package/generated/api/index.js +324 -0
  148. package/generated/api/loader.js +57 -0
  149. package/generated/api/merge.js +88 -0
  150. package/generated/api/model.js +5 -0
  151. package/generated/api/normalize.js +231 -0
  152. package/generated/api/overrides-validate.js +58 -0
  153. package/generated/api/perf.js +12 -0
  154. package/generated/api/registry.js +136 -0
  155. package/generated/api/release.js +44 -0
  156. package/generated/api/resolver.js +250 -0
  157. package/generated/api/sources/aux-types-diff.js +75 -0
  158. package/generated/api/sources/client-tracker.js +11 -0
  159. package/generated/api/sources/creator-docs.js +42 -0
  160. package/generated/api/sources/luau-types.js +34 -0
  161. package/generated/api/sources/mini-dump.js +17 -0
  162. package/generated/api/sources/studio-api.js +8 -0
  163. package/generated/api/sources/studio-apiv2.js +11 -0
  164. package/generated/api/sources/studio-full-api.js +8 -0
  165. package/generated/api/studio-smoke.js +80 -0
  166. package/generated/api/type-parse.js +49 -0
  167. package/generated/api/understander.js +51 -0
  168. package/generated/api/validate.js +135 -0
  169. package/generated/api-cli.js +421 -0
  170. package/generated/cli.js +17 -6
  171. package/generated/clpp/contract.js +3 -3
  172. package/generated/clpp/format-luau.js +236 -0
  173. package/generated/clpp/index.js +13 -1
  174. package/generated/clpp/modules.js +227 -0
  175. package/generated/clpp/postprocess.js +86 -5
  176. package/generated/clpp/rewrite-janitor.js +145 -0
  177. package/generated/clpp/runner.js +14 -2
  178. package/generated/compile.js +82 -0
  179. package/generated/flare/index.js +15 -3
  180. package/generated/flare/language.js +561 -0
  181. package/generated/flare/parse.js +19 -7
  182. package/generated/intellisense.js +76 -2
  183. package/generated/lsp.js +118 -7
  184. package/generated/native/index.js +217 -16
  185. package/generated/target/authority-check.js +136 -0
  186. package/generated/target/authority-graph.js +74 -0
  187. package/generated/target/build-cache.js +112 -0
  188. package/generated/target/capabilities.js +89 -0
  189. package/generated/target/capability-profile.js +30 -0
  190. package/generated/target/component-contracts.js +60 -0
  191. package/generated/target/context-check.js +160 -0
  192. package/generated/target/datamodel-check.js +170 -0
  193. package/generated/target/datamodel-generate.js +74 -0
  194. package/generated/target/datamodel.js +233 -0
  195. package/generated/target/diagnostics.js +63 -0
  196. package/generated/target/doctor.js +152 -0
  197. package/generated/target/flare-version.js +58 -0
  198. package/generated/target/get-service.js +69 -0
  199. package/generated/target/lifetime-check.js +47 -0
  200. package/generated/target/luau-stamp.js +39 -0
  201. package/generated/target/optimizer-advise.js +88 -0
  202. package/generated/target/optimizer-apply.js +44 -0
  203. package/generated/target/optimizer-soa.js +254 -0
  204. package/generated/target/parallel-check.js +136 -0
  205. package/generated/target/pgo.js +148 -0
  206. package/generated/target/project-docs.js +69 -0
  207. package/generated/target/project-graph.js +71 -0
  208. package/generated/target/roblox.js +63 -0
  209. package/generated/target/security-check.js +41 -0
  210. package/generated/target/source-map.js +25 -0
  211. package/generated/target/studio-bridge.js +112 -0
  212. package/generated/utils/project.js +178 -8
  213. package/generated/utils/rojo-mapper.js +11 -3
  214. package/include/clpp/datatypes.clh +337 -373
  215. package/include/clpp/generated/enums.clh +1 -1
  216. package/include/clpp/generated/instances.clh +41135 -41064
  217. package/include/clpp/libs/axiom.clh +1 -1
  218. package/include/clpp/libs/hive.clh +1 -0
  219. package/include/clpp/libs/keep.clh +2 -0
  220. package/include/clpp/libs/math.clh +14 -0
  221. package/include/clpp/libs/roster.clh +6 -0
  222. package/include/clpp/libs/spring.clh +17 -0
  223. package/include/clpp/libs/ward.clh +1 -0
  224. package/include/clpp/roblox.clh +3 -4
  225. package/package.json +10 -3
  226. package/plugins/CluauppNav/Plugin.luau +207 -0
  227. package/plugins/CluauppNav/ProfileLogger.luau +27 -0
  228. package/plugins/CluauppNav/README.md +24 -0
  229. package/runtime/Axiom/init.luau +10 -7
  230. package/runtime/Coil/init.luau +8 -2
  231. package/runtime/Crest/init.luau +1 -0
  232. package/runtime/Flare/init.luau +2 -1
  233. package/runtime/Gleam/init.luau +15 -4
  234. package/runtime/Hive/init.luau +36 -14
  235. package/runtime/Pin/init.luau +5 -2
  236. package/runtime/Roster/init.luau +8 -0
  237. package/runtime/Spark/init.luau +3 -0
  238. package/runtime/Sweep/init.luau +2 -0
  239. package/runtime/Trace/init.luau +3 -0
  240. package/runtime/Ward/init.luau +38 -5
  241. package/scripts/postinstall-editor.js +17 -0
  242. package/skills/README.md +13 -0
  243. package/skills/clpp-hive-flare/SKILL.md +79 -0
  244. package/skills/clpp-language/SKILL.md +123 -0
  245. package/skills/clpp-language/compiler.md +89 -0
  246. package/skills/clpp-style/SKILL.md +95 -0
  247. package/src/api/build-profile.ts +138 -0
  248. package/src/api/cache.ts +45 -0
  249. package/src/api/coverage.ts +46 -0
  250. package/src/api/diff.ts +143 -0
  251. package/src/api/generators/clpp-headers.ts +377 -0
  252. package/src/api/generators/docs-reference.ts +11 -0
  253. package/src/api/generators/lsp-index.ts +106 -0
  254. package/src/api/generators/luau-defs.ts +98 -0
  255. package/src/api/ide.ts +87 -0
  256. package/src/api/identifier.ts +47 -0
  257. package/src/api/index.ts +269 -0
  258. package/src/api/loader.ts +60 -0
  259. package/src/api/merge.ts +126 -0
  260. package/src/api/model.ts +283 -0
  261. package/src/api/normalize.ts +257 -0
  262. package/src/api/overrides-validate.ts +58 -0
  263. package/src/api/perf.ts +15 -0
  264. package/src/api/registry.ts +162 -0
  265. package/src/api/release.ts +47 -0
  266. package/src/api/resolver.ts +255 -0
  267. package/src/api/sources/aux-types-diff.ts +81 -0
  268. package/src/api/sources/client-tracker.ts +10 -0
  269. package/src/api/sources/creator-docs.ts +37 -0
  270. package/src/api/sources/luau-types.ts +30 -0
  271. package/src/api/sources/mini-dump.ts +50 -0
  272. package/src/api/sources/studio-api.ts +7 -0
  273. package/src/api/sources/studio-apiv2.ts +10 -0
  274. package/src/api/sources/studio-full-api.ts +7 -0
  275. package/src/api/studio-smoke.ts +82 -0
  276. package/src/api/type-parse.ts +48 -0
  277. package/src/api/understander.ts +72 -0
  278. package/src/api/validate.ts +160 -0
  279. package/src/api-cli.ts +493 -0
  280. package/src/api.generated.js +37 -22
  281. package/src/cli.ts +22 -7
  282. package/src/clpp/contract.ts +34 -3
  283. package/src/clpp/format-luau.ts +262 -0
  284. package/src/clpp/index.ts +13 -2
  285. package/src/clpp/modules.ts +252 -0
  286. package/src/clpp/postprocess.ts +100 -5
  287. package/src/clpp/rewrite-janitor.ts +156 -0
  288. package/src/clpp/runner.ts +14 -2
  289. package/src/compile.ts +87 -0
  290. package/src/flare/index.ts +20 -1
  291. package/src/flare/language.ts +708 -0
  292. package/src/flare/parse.ts +20 -7
  293. package/src/flare/types.ts +2 -0
  294. package/src/intellisense.ts +76 -2
  295. package/src/lsp.ts +151 -8
  296. package/src/native/index.ts +225 -16
  297. package/src/target/authority-check.ts +162 -0
  298. package/src/target/authority-graph.ts +80 -0
  299. package/src/target/build-cache.ts +129 -0
  300. package/src/target/capabilities.ts +115 -0
  301. package/src/target/capability-profile.ts +25 -0
  302. package/src/target/component-contracts.ts +64 -0
  303. package/src/target/context-check.ts +177 -0
  304. package/src/target/datamodel-check.ts +188 -0
  305. package/src/target/datamodel-generate.ts +78 -0
  306. package/src/target/datamodel.ts +261 -0
  307. package/src/target/diagnostics.ts +67 -0
  308. package/src/target/doctor.ts +171 -0
  309. package/src/target/flare-version.ts +61 -0
  310. package/src/target/get-service.ts +85 -0
  311. package/src/target/lifetime-check.ts +45 -0
  312. package/src/target/luau-stamp.ts +33 -0
  313. package/src/target/optimizer-advise.ts +93 -0
  314. package/src/target/optimizer-apply.ts +63 -0
  315. package/src/target/optimizer-soa.ts +270 -0
  316. package/src/target/parallel-check.ts +135 -0
  317. package/src/target/pgo.ts +157 -0
  318. package/src/target/project-docs.ts +68 -0
  319. package/src/target/project-graph.ts +75 -0
  320. package/src/target/roblox.ts +78 -0
  321. package/src/target/security-check.ts +40 -0
  322. package/src/target/source-map.ts +36 -0
  323. package/src/target/studio-bridge.ts +140 -0
  324. package/src/types.ts +14 -0
  325. package/src/utils/project.ts +183 -9
  326. package/src/utils/rojo-mapper.ts +12 -3
  327. package/stylua.toml +9 -0
  328. package/templates/game/.vscode/extensions.json +3 -1
  329. package/templates/game/.vscode/settings.json +8 -1
  330. package/templates/game/include/clpp/datatypes.clh +337 -373
  331. package/templates/game/include/clpp/generated/enums.clh +1 -1
  332. package/templates/game/include/clpp/generated/instances.clh +41135 -41064
  333. package/templates/game/include/clpp/libs/axiom.clh +1 -1
  334. package/templates/game/include/clpp/libs/roster.clh +6 -0
  335. package/templates/game/include/clpp/libs/ward.clh +1 -0
  336. package/templates/game/include/clpp/roblox.clh +3 -4
  337. package/templates/game/src/ReplicatedStorage/Shared/Net/Net.flare +5 -0
  338. package/templates/game/src/ServerScriptService/Boot/DataBoot.server.clpp +2 -2
  339. package/templates/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
  340. 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
+ }