cluaupp 0.1.2 → 0.1.5
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 +29 -1
- package/README.md +10 -13
- package/docs/README.md +13 -10
- package/docs/architecture.md +30 -73
- package/docs/cli.md +5 -6
- package/docs/comparison.md +3 -3
- package/docs/config.md +6 -6
- package/docs/cpp-advanced.md +10 -6
- package/docs/cpp-organization.md +4 -2
- package/docs/cpp-safety.md +11 -7
- package/docs/cpp-types.md +1 -1
- package/docs/examples/_category_.json +5 -0
- package/docs/examples/combat.md +239 -0
- package/docs/examples/data-boot.md +98 -0
- package/docs/examples/hud.md +96 -0
- package/docs/examples/index.md +43 -0
- package/docs/examples/leaderstats.md +140 -0
- package/docs/examples/shop.md +122 -0
- package/docs/examples/sword.md +108 -0
- package/docs/getting-started.md +14 -7
- package/docs/intellisense.md +31 -0
- package/docs/intro.md +3 -3
- package/docs/libraries/_category_.json +5 -0
- package/docs/libraries/dataservice.md +104 -0
- package/docs/libraries/index.md +22 -0
- package/docs/libraries/janitor.md +65 -0
- package/docs/libraries/more.md +79 -0
- package/docs/libraries/net.md +35 -0
- package/docs/libraries/promise.md +27 -0
- package/docs/oop/_category_.json +5 -0
- package/docs/oop/file-tags.md +48 -0
- package/docs/oop/index.md +22 -0
- package/docs/oop/modules.md +88 -0
- package/docs/oop/services.md +76 -0
- package/docs/print-cout.md +91 -0
- package/docs/syntax.md +63 -8
- package/editors/vscode/extension.js +146 -0
- package/editors/vscode/package.json +25 -0
- package/include/cluaupp/libs/janitor.hpp +7 -3
- package/include/cluaupp/roblox.hpp +19 -0
- package/package.json +66 -65
- package/runtime/Janitor/init.luau +4 -34
- package/src/architecture.js +174 -66
- package/src/cli.js +88 -21
- package/src/client/init.client.cpp +5 -0
- package/src/compile.js +77 -7
- package/src/editor-install.js +218 -0
- package/src/emit.js +321 -9
- package/src/headers.js +234 -0
- package/src/intellisense.js +1368 -0
- package/src/layout.js +129 -0
- package/src/lex.js +17 -9
- package/src/libs.js +165 -18
- package/src/lsp.js +227 -0
- package/src/parse.js +187 -6
- package/src/preprocess.js +118 -3
- package/src/server/leaderstats.server.cpp +28 -0
- package/src/shared/config.cpp +5 -0
- package/src/shared/config.h +3 -0
- package/src/understand.js +66 -6
- package/templates/game/.clangd +11 -0
- package/templates/game/.vscode/c_cpp_properties.json +6 -2
- package/templates/game/.vscode/extensions.json +6 -0
- package/templates/game/.vscode/settings.json +16 -2
- package/templates/game/cluaupp.config.json +2 -2
- package/templates/game/compile_flags.txt +2 -0
- package/templates/game/src/client/init.client.cpp +1 -0
- package/templates/game/src/server/leaderstats.server.cpp +1 -0
- package/docs/libraries.md +0 -80
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Shop
|
|
3
|
+
sidebar_position: 5
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Shop
|
|
7
|
+
|
|
8
|
+
The client sends **which product**. The server looks up the price, checks Money, then `Set`. Never let the client send the new balance or the price.
|
|
9
|
+
|
|
10
|
+
## Catalog header
|
|
11
|
+
|
|
12
|
+
`src/shared/constants/ShopCatalog.hpp`
|
|
13
|
+
|
|
14
|
+
Cluaupp has no maps. A function with early returns is the catalog.
|
|
15
|
+
|
|
16
|
+
```cpp
|
|
17
|
+
#pragma once
|
|
18
|
+
|
|
19
|
+
const int PRODUCT_HEALTH_PACK = 1;
|
|
20
|
+
const int PRODUCT_SPEED_TOME = 2;
|
|
21
|
+
|
|
22
|
+
int PriceOf(int productId) {
|
|
23
|
+
if (productId == PRODUCT_HEALTH_PACK) {
|
|
24
|
+
return 50;
|
|
25
|
+
}
|
|
26
|
+
if (productId == PRODUCT_SPEED_TOME) {
|
|
27
|
+
return 200;
|
|
28
|
+
}
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`PriceOf` lives in a header so the **server** is the copy that matters. The client may include it for UI labels, but a patched client cannot change what the server charges.
|
|
34
|
+
|
|
35
|
+
## Server — `ShopServer.server.cpp`
|
|
36
|
+
|
|
37
|
+
```cpp
|
|
38
|
+
#include <cluaupp/roblox.hpp>
|
|
39
|
+
#include <cluaupp/libs/janitor.hpp>
|
|
40
|
+
#include <cluaupp/libs/net.hpp>
|
|
41
|
+
#include <cluaupp/libs/dataservice.hpp>
|
|
42
|
+
#include "../../../shared/constants/ShopCatalog.hpp"
|
|
43
|
+
|
|
44
|
+
Janitor* janitor = new Janitor();
|
|
45
|
+
NetEvent* Buy = Net::Event("Buy");
|
|
46
|
+
|
|
47
|
+
void ApplyProduct(Player* player, int productId) {
|
|
48
|
+
Model* character = player->Character;
|
|
49
|
+
if (character == nullptr) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
Humanoid* humanoid = character->FindFirstChildOfClass("Humanoid");
|
|
53
|
+
if (humanoid == nullptr) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (productId == PRODUCT_HEALTH_PACK) {
|
|
57
|
+
humanoid->Health = humanoid->MaxHealth;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (productId == PRODUCT_SPEED_TOME) {
|
|
61
|
+
humanoid->WalkSpeed = 24;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void OnBuy(Player* player, int productId) {
|
|
67
|
+
int price = PriceOf(productId);
|
|
68
|
+
if (price < 1) {
|
|
69
|
+
cout::warn << "unknown product " << productId << endl;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
Data* data = DataService::Server.WaitFor(player);
|
|
73
|
+
if (data == nullptr) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
int money = data->Get(DataService::Server.Paths.Currencies.Money);
|
|
77
|
+
if (money < price) {
|
|
78
|
+
cout::ping << player->Name << " cannot afford " << productId << endl;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
data->Set(DataService::Server.Paths.Currencies.Money, money - price);
|
|
82
|
+
ApplyProduct(player, productId);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
void init() {
|
|
86
|
+
Buy->On(OnBuy);
|
|
87
|
+
janitor->Add(Buy);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Debit **before** (or atomically with) the effect. If you grant the item first and the `Set` fails, the player dupes.
|
|
92
|
+
|
|
93
|
+
## Client — `ShopClient.client.cpp`
|
|
94
|
+
|
|
95
|
+
```cpp
|
|
96
|
+
#include <cluaupp/roblox.hpp>
|
|
97
|
+
#include <cluaupp/libs/janitor.hpp>
|
|
98
|
+
#include <cluaupp/libs/net.hpp>
|
|
99
|
+
#include "../../../shared/constants/ShopCatalog.hpp"
|
|
100
|
+
|
|
101
|
+
Janitor* janitor = new Janitor();
|
|
102
|
+
NetEvent* Buy = Net::Event("Buy");
|
|
103
|
+
|
|
104
|
+
void OnHealthPackClicked() {
|
|
105
|
+
Buy->FireServer(PRODUCT_HEALTH_PACK);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void init() {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Wire `OnHealthPackClicked` to a `TextButton->MouseButton1Click.Connect(OnHealthPackClicked)` when you have the GUI. The remote payload is only the product id.
|
|
114
|
+
|
|
115
|
+
## Rules
|
|
116
|
+
|
|
117
|
+
- `productId < 1` / unknown id → `PriceOf` returns `0` → reject.
|
|
118
|
+
- Do not `FireServer(price)` or `FireServer(newMoney)`.
|
|
119
|
+
- [Leaderstats](leaderstats.md) updates from `GetChangedSignal` after `Set`.
|
|
120
|
+
- Same Net name `"Buy"` on both sides.
|
|
121
|
+
|
|
122
|
+
See [Safety](../cpp-safety.md).
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Sword (Touched)
|
|
3
|
+
sidebar_position: 7
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sword (Touched)
|
|
7
|
+
|
|
8
|
+
Melee that uses a **server** `Touched` on the tool handle. The client can play animations; it must not tell the server how much damage to apply.
|
|
9
|
+
|
|
10
|
+
Same authority as [combat](combat.md), without a Net remote: while the Tool is equipped, `Touched` runs on the server.
|
|
11
|
+
|
|
12
|
+
## Config
|
|
13
|
+
|
|
14
|
+
`src/shared/constants/SwordConfig.hpp`
|
|
15
|
+
|
|
16
|
+
```cpp
|
|
17
|
+
#pragma once
|
|
18
|
+
|
|
19
|
+
const double SWORD_COOLDOWN = 0.35;
|
|
20
|
+
const int SWORD_DAMAGE = 18;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Script inside the Tool
|
|
24
|
+
|
|
25
|
+
Put the source next to the Tool so `script->Parent` is the `Tool`. Use **`.legacy.server.cpp`** so Cluaupp emits a 1:1 Script (no Main/Controller split) that Rojo can parent under `ClassicSword`.
|
|
26
|
+
|
|
27
|
+
`src/server/tools/Sword.legacy.server.cpp`
|
|
28
|
+
|
|
29
|
+
```cpp
|
|
30
|
+
#include <cluaupp/roblox.hpp>
|
|
31
|
+
#include "../../shared/constants/SwordConfig.hpp"
|
|
32
|
+
|
|
33
|
+
Players* Players = GetService<Players>();
|
|
34
|
+
Tool* tool = script->Parent;
|
|
35
|
+
|
|
36
|
+
void OnTouched(Instance* hit) {
|
|
37
|
+
if (hit == nullptr) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Player* attacker = Players->GetPlayerFromCharacter(tool->Parent);
|
|
42
|
+
if (attacker == nullptr) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
NumberValue* last = attacker->FindFirstChild("LastSwordAt");
|
|
47
|
+
if (last != nullptr) {
|
|
48
|
+
if (tick() - last->Value < SWORD_COOLDOWN) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Instance* model = hit->FindFirstAncestorOfClass("Model");
|
|
54
|
+
if (model == nullptr) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
Player* victim = Players->GetPlayerFromCharacter(model);
|
|
58
|
+
if (victim == nullptr) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (victim == attacker) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Humanoid* humanoid = model->FindFirstChildOfClass("Humanoid");
|
|
66
|
+
if (humanoid == nullptr) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (humanoid->Health <= 0) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (last == nullptr) {
|
|
74
|
+
last = new NumberValue(attacker);
|
|
75
|
+
last->Name = "LastSwordAt";
|
|
76
|
+
}
|
|
77
|
+
last->Value = tick();
|
|
78
|
+
humanoid->TakeDamage(SWORD_DAMAGE);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void init() {
|
|
82
|
+
BasePart* handle = tool->FindFirstChild("Handle");
|
|
83
|
+
if (handle == nullptr) {
|
|
84
|
+
cout::warn << "ClassicSword missing Handle" << endl;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
handle->Touched.Connect(OnTouched);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`tool->Parent` is the Character while equipped, `nil` in the backpack — `GetPlayerFromCharacter` then fails and the swing is ignored. That is what you want.
|
|
92
|
+
|
|
93
|
+
## Why `.legacy`
|
|
94
|
+
|
|
95
|
+
A tagged `Sword.server.cpp` in `src/server/` becomes a service folder in ServerScriptService. A Tool Script must live **under the Tool**. Legacy keeps one file you can Rojo-map into `ClassicSword`.
|
|
96
|
+
|
|
97
|
+
## Rules
|
|
98
|
+
|
|
99
|
+
| Do | Do not |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `TakeDamage(SWORD_DAMAGE)` on the server | `FireServer(damage)` from a LocalScript |
|
|
102
|
+
| Skip `victim == attacker` | Damage the owner when the handle clips their own parts |
|
|
103
|
+
| Cooldown on the attacker | Trust `Touched` rate (it fires every physics step) |
|
|
104
|
+
| `GetPlayerFromCharacter` | Treat every Humanoid as a player if you only want PvP |
|
|
105
|
+
|
|
106
|
+
Client: a LocalScript in the same Tool can play an AnimationTrack on `Activated`. It still must not replicate a damage number.
|
|
107
|
+
|
|
108
|
+
For ranged hits (mouse target → remote), use [combat](combat.md).
|
package/docs/getting-started.md
CHANGED
|
@@ -66,7 +66,8 @@ my-game/
|
|
|
66
66
|
shared/config.h
|
|
67
67
|
shared/config.cpp
|
|
68
68
|
out/ ← generated Luau (do not edit)
|
|
69
|
-
server/
|
|
69
|
+
server/leaderstats.server.luau
|
|
70
|
+
client/init.client.luau
|
|
70
71
|
shared/Config.luau
|
|
71
72
|
```
|
|
72
73
|
|
|
@@ -122,13 +123,15 @@ If a file defines `void init()`, Cluaupp calls `init()` at the end of the `.luau
|
|
|
122
123
|
|
|
123
124
|
## IntelliSense
|
|
124
125
|
|
|
125
|
-
`cluaupp init`
|
|
126
|
+
`cluaupp init` writes the C++ IntelliSense config and installs Microsoft `ms-vscode.cpptools` (via VSIX on Cursor). Then reload the window.
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
```bash
|
|
129
|
+
cluaupp intellisense
|
|
130
|
+
```
|
|
128
131
|
|
|
129
|
-
|
|
132
|
+
`#include <cluaupp/roblox.hpp>` at the top of each source file. The header is **not** compiled to Luau.
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
See [IntelliSense](intellisense.md).
|
|
132
135
|
|
|
133
136
|
## Watch
|
|
134
137
|
|
|
@@ -153,17 +156,21 @@ void init() {
|
|
|
153
156
|
}
|
|
154
157
|
```
|
|
155
158
|
|
|
156
|
-
Wally is optional. Fusion, Cmdr, DataServiceV2, and the rest ship **inside** `libs/` (full GitHub source). See [Libraries](libraries.md).
|
|
159
|
+
Wally is optional. Fusion, Cmdr, DataServiceV2, and the rest ship **inside** `libs/` (full GitHub source). See [Libraries](libraries/index.md) — start with [DataService Init](libraries/dataservice.md) and [Janitor](libraries/janitor.md).
|
|
157
160
|
|
|
158
|
-
See [Libraries](libraries.md), [types](cpp-types.md), [safety](cpp-safety.md).
|
|
161
|
+
See [Libraries](libraries/index.md), [OOP](oop/index.md), [types](cpp-types.md), [safety](cpp-safety.md).
|
|
159
162
|
|
|
160
163
|
## Next
|
|
161
164
|
|
|
162
165
|
- [C++ → Luau syntax](syntax.md)
|
|
166
|
+
- [print and cout](print-cout.md)
|
|
163
167
|
- [C++ types](cpp-types.md)
|
|
164
168
|
- [const](cpp-const.md)
|
|
165
169
|
- [Safety](cpp-safety.md)
|
|
166
170
|
- [Organization](cpp-organization.md)
|
|
167
171
|
- [Architecture](architecture.md)
|
|
172
|
+
- [OOP structure](oop/index.md)
|
|
173
|
+
- [Libraries](libraries/index.md)
|
|
174
|
+
- [Examples](examples/index.md)
|
|
168
175
|
- [Roblox API](roblox-api.md)
|
|
169
176
|
- [CLI](cli.md)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# IntelliSense
|
|
2
|
+
|
|
3
|
+
`cluaupp init` and `cluaupp intellisense` install the same setup that works in Cursor:
|
|
4
|
+
|
|
5
|
+
1. Microsoft [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) (`ms-vscode.cpptools`)
|
|
6
|
+
2. `.vscode/c_cpp_properties.json` — LLVM `clang++`, C++20, `include/` + `src/`, `compile_commands.json`
|
|
7
|
+
3. Forced include of `include/cluaupp/roblox.hpp` so `GetService`, `Player`, `Janitor` complete
|
|
8
|
+
4. The Cluaupp completion engine (Roblox APIs + your `struct`s)
|
|
9
|
+
|
|
10
|
+
Cursor’s marketplace does not list `ms-vscode.cpptools`. Cluaupp downloads the official VSIX from [vscode-cpptools releases](https://github.com/microsoft/vscode-cpptools/releases) and runs `cursor --install-extension`.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cluaupp intellisense
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Reload: Command Palette → **Developer: Reload Window**. Status bar `{} C++` should read **IntelliSense: Ready**.
|
|
19
|
+
|
|
20
|
+
`cluaupp build` / `watch` only refresh `compile_commands.json` (no download). They never keep deleted files in the compilation database.
|
|
21
|
+
|
|
22
|
+
## Config that ships
|
|
23
|
+
|
|
24
|
+
| File | Role |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `.vscode/c_cpp_properties.json` | compiler path, include path, `compileCommands` |
|
|
27
|
+
| `.vscode/settings.json` | `C_Cpp.intelliSenseEngine: default`, `clangd.enable: false` |
|
|
28
|
+
| `.vscode/extensions.json` | recommends `ms-vscode.cpptools` |
|
|
29
|
+
| `compile_commands.json` | one entry per `src/` file |
|
|
30
|
+
|
|
31
|
+
`#include <cluaupp/roblox.hpp>` at the top of each source file. The header is not compiled to Luau.
|
package/docs/intro.md
CHANGED
|
@@ -5,9 +5,9 @@ sidebar_position: 1
|
|
|
5
5
|
|
|
6
6
|
# Cluaupp
|
|
7
7
|
|
|
8
|
-
**The definitive merge of C++ and modern Luau.** You write a C++ subset. Cluaupp emits [Luau](https://luau.org/getting-started) with
|
|
8
|
+
**The definitive merge of C++ and modern Luau.** You write a C++ subset. Cluaupp emits [Luau](https://luau.org/getting-started) with `local` and `const` (and `--!strict` when you opt in), and calls the Roblox API the way Studio does.
|
|
9
9
|
|
|
10
|
-
This site is built with [Moonwave](https://eryn.io/moonwave/) for local markdown
|
|
10
|
+
This site is built with [Moonwave](https://eryn.io/moonwave/) for local markdown (`npm run docs`). The **public** site is generated into `site/` and deployed to [GitHub Pages](https://kartzrbx.github.io/Cluaupp/) (Learn tabs, OOP, Examples, API). The language is in the same spirit as [roblox-ts](https://roblox-ts.com): a familiar syntax, a restricted subset, readable output.
|
|
11
11
|
|
|
12
12
|
## What you get
|
|
13
13
|
|
|
@@ -34,4 +34,4 @@ void init() {
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Read [Getting started](getting-started.md), then [
|
|
37
|
+
Read [Getting started](getting-started.md), then [Examples](examples/index.md), [Libraries](libraries/index.md), and [OOP structure](oop/index.md).
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: DataService
|
|
3
|
+
sidebar_position: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DataService
|
|
7
|
+
|
|
8
|
+
Player profiles (DataServiceV2). Header: `#include <cluaupp/libs/dataservice.hpp>`.
|
|
9
|
+
|
|
10
|
+
The **save shape is yours**. Do not put `Currencies` / `Money` on the library `DataPath` type. Define a struct in the game (shared header) and pass it as `.Template`.
|
|
11
|
+
|
|
12
|
+
## 1. Template (shared)
|
|
13
|
+
|
|
14
|
+
```cpp
|
|
15
|
+
#pragma once
|
|
16
|
+
|
|
17
|
+
struct TemplateData {
|
|
18
|
+
struct Currencies {
|
|
19
|
+
int Money = 0;
|
|
20
|
+
int Level = 1;
|
|
21
|
+
} Currencies;
|
|
22
|
+
};
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Luau `DataService.Paths` follows this table (`Paths.Currencies.Money`).
|
|
26
|
+
|
|
27
|
+
## 2. Start the server
|
|
28
|
+
|
|
29
|
+
Call **once** from a server boot script (`DataBoot.server.cpp`). `void init()` is what Cluaupp runs (not `int main()`).
|
|
30
|
+
|
|
31
|
+
```cpp
|
|
32
|
+
#include <cluaupp/roblox.hpp>
|
|
33
|
+
#include <cluaupp/libs/dataservice.hpp>
|
|
34
|
+
#include "../../shared/constants/TemplateData.hpp"
|
|
35
|
+
|
|
36
|
+
void init() {
|
|
37
|
+
TemplateData playerData = TemplateData {};
|
|
38
|
+
DataService::Server.Init(DataServiceOptions {
|
|
39
|
+
.Template = playerData,
|
|
40
|
+
.StoreName = "PlayerData",
|
|
41
|
+
.UseMock = true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
| Field | Meaning |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `.Template` | Default document. Must match the save struct. |
|
|
49
|
+
| `.StoreName` | DataStore name (or a version string you own). |
|
|
50
|
+
| `.UseMock` | `true` in Studio / tests so you do not hit the live store. |
|
|
51
|
+
| `.KeyPrefix` | Optional prefix on profile keys. |
|
|
52
|
+
| `.StrictPaths` | Reject unknown path segments. |
|
|
53
|
+
| `.AutoCreateMissingTables` | Create missing nested tables on write. |
|
|
54
|
+
|
|
55
|
+
## 3. Start the client
|
|
56
|
+
|
|
57
|
+
```cpp
|
|
58
|
+
#include <cluaupp/roblox.hpp>
|
|
59
|
+
#include <cluaupp/libs/dataservice.hpp>
|
|
60
|
+
|
|
61
|
+
void init() {
|
|
62
|
+
DataService::Client.Init();
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 4. Read / wait
|
|
67
|
+
|
|
68
|
+
```cpp
|
|
69
|
+
Data* data = DataService::Server.WaitFor(player);
|
|
70
|
+
if (data == nullptr) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
int money = data->Get(DataService::Server.Paths.Currencies.Money);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- `WaitFor` — yield until the profile exists.
|
|
78
|
+
- `Get(player)` — already loaded or `nullptr`.
|
|
79
|
+
- `data->Get()` with no path — whole table.
|
|
80
|
+
- `GetPersisted` / `GetTransient` — saved vs session-only.
|
|
81
|
+
|
|
82
|
+
Client: `DataService::Client.WaitForData()` / `Get()`.
|
|
83
|
+
|
|
84
|
+
## 5. Write and listen
|
|
85
|
+
|
|
86
|
+
```cpp
|
|
87
|
+
data->Set(DataService::Server.Paths.Currencies.Money, 10);
|
|
88
|
+
|
|
89
|
+
void OnCurrenciesChanged() {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
data->GetChangedSignal(DataService::Server.Paths.Currencies).Connect(OnCurrenciesChanged);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`GetChangedSignal` fires when that path (or a child) changes. Cluaupp has no lambdas — use a named function.
|
|
97
|
+
|
|
98
|
+
## Rules
|
|
99
|
+
|
|
100
|
+
- Init on **server and client**. Writes that must persist belong on the server.
|
|
101
|
+
- Paths are not a C++ enum in the library. They exist because your Template was passed to `Init`.
|
|
102
|
+
- Keep boot (`Init`) in one file. Keep HUD / leaderstats in another and `WaitFor` there.
|
|
103
|
+
|
|
104
|
+
Full copies: [Data boot](../examples/data-boot.md), [Leaderstats](../examples/leaderstats.md), [HUD](../examples/hud.md).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Using libraries
|
|
3
|
+
sidebar_position: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Libraries
|
|
7
|
+
|
|
8
|
+
`#include <cluaupp/libs/...hpp>` is IntelliSense. `cluaupp build` copies the real Luau into `libs/` (`ReplicatedStorage.CluauppLibs`). You do not `require` by hand in C++.
|
|
9
|
+
|
|
10
|
+
| Guide | Use it when |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| [DataService](dataservice.md) | Player save data, `Init`, `WaitFor`, `GetChangedSignal` |
|
|
13
|
+
| [Janitor](janitor.md) | Connections, instances, cleanup on leave |
|
|
14
|
+
| [Promise](promise.md) | Delay, Then / Catch / Await |
|
|
15
|
+
| [Net](net.md) | RemoteEvent / RemoteFunction without making remotes |
|
|
16
|
+
| [More libraries](more.md) | FormatNumber, Fusion, Cmdr, Twinkle, MathUtils, … |
|
|
17
|
+
|
|
18
|
+
Sources: [runtime/SOURCES.md](https://github.com/KartzRbx/Cluaupp/blob/main/runtime/SOURCES.md). Re-vendor: `node scripts/vendor-libs.js`.
|
|
19
|
+
|
|
20
|
+
Wally is optional. Do not install a second Janitor from Wally — CluauppLibs already has howmanysmall/Janitor.
|
|
21
|
+
|
|
22
|
+
Copy-paste systems: [Examples](../examples/index.md).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Janitor
|
|
3
|
+
sidebar_position: 3
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Janitor
|
|
7
|
+
|
|
8
|
+
Cleans connections, instances, promises, and threads. Header: `#include <cluaupp/libs/janitor.hpp>`. Runtime is [howmanysmall/Janitor](https://github.com/howmanysmall/Janitor). Types come from `_impl` — there is no fake `Has` method.
|
|
9
|
+
|
|
10
|
+
## Create and add
|
|
11
|
+
|
|
12
|
+
```cpp
|
|
13
|
+
auto* janitor = new Janitor();
|
|
14
|
+
|
|
15
|
+
janitor->Add(Players->PlayerAdded.Connect(OnPlayer));
|
|
16
|
+
janitor->Add(part, "Destroy");
|
|
17
|
+
janitor->Add(print, true);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Call | Cleanup |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `Add(connection)` | `Disconnect` |
|
|
23
|
+
| `Add(instance)` / `Add(instance, "Destroy")` | `Destroy` |
|
|
24
|
+
| `Add(fn, true)` | call the function |
|
|
25
|
+
| `Add(thread, true)` | `task.cancel` |
|
|
26
|
+
|
|
27
|
+
## Indexed slots (per player)
|
|
28
|
+
|
|
29
|
+
The third argument is a namespace. Adding again with the same index removes the previous task first.
|
|
30
|
+
|
|
31
|
+
```cpp
|
|
32
|
+
janitor->Add(sectionJanitor, "Destroy", player->Name);
|
|
33
|
+
|
|
34
|
+
if (janitor->Get(player->Name)) {
|
|
35
|
+
janitor->Remove(player->Name);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`Remove` on a missing index is a no-op. There is **no** `Has` — use `Get`.
|
|
40
|
+
|
|
41
|
+
## Lifetime
|
|
42
|
+
|
|
43
|
+
```cpp
|
|
44
|
+
janitor->Cleanup();
|
|
45
|
+
janitor->Destroy();
|
|
46
|
+
janitor->LinkToInstance(player);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `Cleanup` — run every task, janitor stays usable.
|
|
50
|
+
- `Destroy` — cleanup and freeze the object.
|
|
51
|
+
- `LinkToInstance` — cleanup when that Instance is destroyed.
|
|
52
|
+
|
|
53
|
+
## Promises
|
|
54
|
+
|
|
55
|
+
```cpp
|
|
56
|
+
#include <cluaupp/libs/promise.hpp>
|
|
57
|
+
|
|
58
|
+
janitor->AddPromise(Promise::delay(1));
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Cleanup cancels or rejects the promise when the janitor runs.
|
|
62
|
+
|
|
63
|
+
## Pattern
|
|
64
|
+
|
|
65
|
+
One janitor for the script. A **child** janitor per player, stored under `player->Name`, removed on `PlayerRemoving`. Copy: [Leaderstats](../examples/leaderstats.md).
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: More libraries
|
|
3
|
+
sidebar_position: 6
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# More libraries
|
|
7
|
+
|
|
8
|
+
Same rule: include the header, call the API. `cluaupp build` already put the Luau in `CluauppLibs`.
|
|
9
|
+
|
|
10
|
+
## FormatNumber
|
|
11
|
+
|
|
12
|
+
```cpp
|
|
13
|
+
#include <cluaupp/libs/formatnumber.hpp>
|
|
14
|
+
|
|
15
|
+
print(FormatNumber::Abbreviate(1500));
|
|
16
|
+
print(FormatNumber::Comma(1500));
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## MathUtils
|
|
20
|
+
|
|
21
|
+
```cpp
|
|
22
|
+
#include <cluaupp/libs/math.hpp>
|
|
23
|
+
|
|
24
|
+
double t = MathUtils::Lerp(0, 1, 0.5);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Twinkle (UI)
|
|
28
|
+
|
|
29
|
+
```cpp
|
|
30
|
+
#include <cluaupp/libs/twinkle.hpp>
|
|
31
|
+
|
|
32
|
+
Twinkle::Fade(frame, true);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Module3D
|
|
36
|
+
|
|
37
|
+
```cpp
|
|
38
|
+
#include <cluaupp/libs/module3d.hpp>
|
|
39
|
+
|
|
40
|
+
Module3D::Attach3D(viewport, model);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## VfxUtil
|
|
44
|
+
|
|
45
|
+
```cpp
|
|
46
|
+
#include <cluaupp/libs/vfx.hpp>
|
|
47
|
+
|
|
48
|
+
VfxUtil::Emit(root);
|
|
49
|
+
VfxUtil::Play(emitter);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## StickyBillboard
|
|
53
|
+
|
|
54
|
+
```cpp
|
|
55
|
+
#include <cluaupp/libs/stickybillboard.hpp>
|
|
56
|
+
|
|
57
|
+
auto* billboard = StickyBillboard::new_(adornee, gui);
|
|
58
|
+
billboard->SetText("Hello");
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Fusion / Iris / Cmdr / TopbarPlus / Chrono / EzVisualz / StateMachine / Spring / Display
|
|
62
|
+
|
|
63
|
+
These are the GitHub systems behind typed `init.luau` borders. Include the matching `<cluaupp/libs/*.hpp>` and call the same names as the upstream README. Cluaupp does not re-document every Fusion `Value` / Cmdr command — use:
|
|
64
|
+
|
|
65
|
+
| Lib | Header | Upstream |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| Fusion | `fusion.hpp` | [dphfox/Fusion](https://github.com/dphfox/Fusion) |
|
|
68
|
+
| Iris | `iris.hpp` | [SirMallard/Iris](https://github.com/SirMallard/Iris) |
|
|
69
|
+
| Cmdr | `cmdr.hpp` | [evaera/Cmdr](https://github.com/evaera/Cmdr) |
|
|
70
|
+
| TopbarPlus | `topbarplus.hpp` | [1ForeverHD/TopbarPlus](https://github.com/1ForeverHD/TopbarPlus) |
|
|
71
|
+
| Chrono | `chrono.hpp` | [Parihsz/Chrono](https://github.com/Parihsz/Chrono) |
|
|
72
|
+
| EzVisualz | `ezvisual.hpp` | [arxkdev/ezVisualz](https://github.com/arxkdev/ezVisualz) |
|
|
73
|
+
| StateMachine | `statemachine.hpp` | [Prooheckcp/RobloxStateMachine](https://github.com/Prooheckcp/RobloxStateMachine) |
|
|
74
|
+
| Spring | `spring.hpp` | [nightcycle/spring](https://github.com/nightcycle/spring) |
|
|
75
|
+
| Display | `display.hpp` | [nightcycle/display](https://github.com/nightcycle/display) |
|
|
76
|
+
|
|
77
|
+
## Types-only
|
|
78
|
+
|
|
79
|
+
`ArrayIndexer` (`Table<Manifest, "Name">`) and `Occlude` (`Keys<Data, "field">`) are used by generated `{Service}Types.luau`. You rarely include them from game C++.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Net
|
|
3
|
+
sidebar_position: 5
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Net
|
|
7
|
+
|
|
8
|
+
Buffer-packed remotes. Header: `#include <cluaupp/libs/net.hpp>`. Same name on server and client — you do not create `RemoteEvent` instances yourself.
|
|
9
|
+
|
|
10
|
+
```cpp
|
|
11
|
+
#include <cluaupp/roblox.hpp>
|
|
12
|
+
#include <cluaupp/libs/net.hpp>
|
|
13
|
+
#include <cluaupp/libs/janitor.hpp>
|
|
14
|
+
|
|
15
|
+
void OnCoins(Player* player, int amount) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void init() {
|
|
20
|
+
auto* janitor = new Janitor();
|
|
21
|
+
auto* coins = Net::Event("Coins");
|
|
22
|
+
coins->On(OnCoins);
|
|
23
|
+
janitor->Add(coins);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| Side | API |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Server | `Fire(player, ...)`, `FireAll(...)` |
|
|
30
|
+
| Client | `FireServer(...)` |
|
|
31
|
+
| Both | `On(callback)` |
|
|
32
|
+
|
|
33
|
+
Functions: `Net::Function("Shop")`, then `Invoke` / `InvokeServer`.
|
|
34
|
+
|
|
35
|
+
Validate everything the client fires. See [safety](../cpp-safety.md). Full copies: [Combat](../examples/combat.md), [Shop](../examples/shop.md).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Promise
|
|
3
|
+
sidebar_position: 4
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Promise
|
|
7
|
+
|
|
8
|
+
[evaera/roblox-lua-promise](https://github.com/evaera/roblox-lua-promise). Header: `#include <cluaupp/libs/promise.hpp>`.
|
|
9
|
+
|
|
10
|
+
C++ names `Then` / `Catch` / `Await` / `Cancel` are aliases of `andThen` / `catch` / `await` / `cancel`.
|
|
11
|
+
|
|
12
|
+
```cpp
|
|
13
|
+
#include <cluaupp/roblox.hpp>
|
|
14
|
+
#include <cluaupp/libs/promise.hpp>
|
|
15
|
+
|
|
16
|
+
void AfterWait() {
|
|
17
|
+
print("1s later");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
void init() {
|
|
21
|
+
Promise::delay(1);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Useful statics: `Promise::delay(seconds)`, `Promise::resolve(value)`, `Promise::reject("err")`.
|
|
26
|
+
|
|
27
|
+
Cluaupp cannot nest lambdas. Prefer `delay` plus a named callback you already have, or keep promise chains in Luau libraries you call from C++.
|