cluaupp 0.2.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -79
- package/README.md +42 -88
- package/docs/README.md +13 -21
- package/docs/architecture.md +13 -76
- package/docs/cli.md +12 -64
- package/docs/comparison.md +6 -24
- package/docs/config.md +6 -7
- package/docs/examples/combat.md +19 -227
- package/docs/examples/hud.md +13 -81
- package/docs/examples/index.md +9 -16
- package/docs/getting-started.md +20 -137
- package/docs/intellisense.md +5 -41
- package/docs/intro.md +16 -15
- package/docs/migration.md +38 -0
- package/docs/oop/file-tags.md +12 -36
- package/docs/oop/index.md +8 -14
- package/docs/syntax.md +54 -236
- package/editors/vscode/extension.js +1 -1
- package/editors/vscode/package.json +4 -4
- package/examples/README.md +5 -7
- package/examples/game/.vscode/extensions.json +0 -3
- package/examples/game/.vscode/settings.json +6 -14
- package/examples/game/src/client/hud.client.clpp +54 -0
- package/examples/game/src/client/init.client.clpp +6 -0
- package/examples/game/src/server/combat.server.clpp +85 -0
- package/examples/game/src/server/leaderstats.server.clpp +28 -0
- package/examples/game/src/shared/PlayerData.clh +20 -0
- package/examples/game/src/shared/config.clp +6 -0
- package/examples/game/src/shared/features.clp +88 -0
- package/generated/cli.js +40 -24
- package/generated/clpp/contract.js +5 -0
- package/generated/clpp/index.js +27 -0
- package/generated/clpp/paths.js +121 -0
- package/generated/clpp/postprocess.js +78 -0
- package/generated/clpp/runner.js +102 -0
- package/generated/compile.js +26 -138
- package/generated/intellisense.js +38 -157
- package/generated/libs.js +1 -1
- package/generated/lsp.js +1 -8
- package/generated/preprocess.js +8 -179
- package/generated/system-understander.js +1 -1
- package/generated/transpile.js +3 -50
- package/generated/utils/project.js +13 -28
- package/include/{cluaupp/datatypes.hpp → clpp/datatypes.clh} +1 -1
- package/include/{cluaupp/generated/instances.hpp → clpp/generated/instances.clh} +1 -1
- package/include/{cluaupp/libs/chrono.hpp → clpp/libs/chrono.clh} +9 -9
- package/include/{cluaupp/libs/cmdr.hpp → clpp/libs/cmdr.clh} +4 -4
- package/include/{cluaupp/libs/dataservice.hpp → clpp/libs/dataservice.clh} +8 -15
- package/include/{cluaupp/libs/display.hpp → clpp/libs/display.clh} +1 -2
- package/include/{cluaupp/libs/ezvisual.hpp → clpp/libs/ezvisual.clh} +1 -3
- package/include/{cluaupp/libs/formatnumber.hpp → clpp/libs/formatnumber.clh} +2 -3
- package/include/{cluaupp/libs/fusion.hpp → clpp/libs/fusion.clh} +5 -5
- package/include/{cluaupp/libs/iris.hpp → clpp/libs/iris.clh} +2 -2
- package/include/{cluaupp/libs/janitor.hpp → clpp/libs/janitor.clh} +1 -2
- package/include/{cluaupp/libs/module3d.hpp → clpp/libs/module3d.clh} +2 -4
- package/include/{cluaupp/libs/net.hpp → clpp/libs/net.clh} +2 -4
- package/include/{cluaupp/libs/promise.hpp → clpp/libs/promise.clh} +1 -4
- package/include/{cluaupp/libs/spring.hpp → clpp/libs/spring.clh} +1 -2
- package/include/{cluaupp/libs/statemachine.hpp → clpp/libs/statemachine.clh} +2 -3
- package/include/{cluaupp/libs/stickybillboard.hpp → clpp/libs/stickybillboard.clh} +1 -2
- package/include/{cluaupp/libs/topbarplus.hpp → clpp/libs/topbarplus.clh} +3 -4
- package/include/clpp/libs.clh +24 -0
- package/include/clpp/roblox.clh +31 -0
- package/package.json +7 -14
- package/src/cli.ts +39 -25
- package/src/clpp/contract.ts +39 -0
- package/src/clpp/index.ts +18 -0
- package/src/clpp/paths.ts +117 -0
- package/src/clpp/postprocess.ts +93 -0
- package/src/clpp/runner.ts +102 -0
- package/src/compile.ts +26 -149
- package/src/intellisense.ts +36 -165
- package/src/libs.ts +1 -1
- package/src/lsp.ts +1 -5
- package/src/preprocess.ts +8 -180
- package/src/system-understander.ts +1 -1
- package/src/transpile.ts +9 -52
- package/src/utils/project.ts +12 -28
- package/templates/game/.vscode/extensions.json +0 -3
- package/templates/game/.vscode/settings.json +6 -14
- package/templates/game/src/client/init.client.clpp +6 -0
- package/templates/game/src/server/leaderstats.server.clpp +29 -0
- package/templates/game/src/shared/config.clp +6 -0
- package/examples/game/.clangd +0 -25
- package/examples/game/compile_flags.txt +0 -6
- package/examples/game/src/client/hud.client.cpp +0 -12
- package/examples/game/src/client/init.client.cpp +0 -6
- package/examples/game/src/server/combat.server.cpp +0 -23
- package/examples/game/src/server/leaderstats.server.cpp +0 -29
- package/examples/game/src/shared/config.cpp +0 -5
- package/examples/game/src/shared/config.h +0 -5
- package/include/cluaupp/libs.hpp +0 -25
- package/include/cluaupp/roblox.hpp +0 -47
- package/src/architecture.ts +0 -500
- package/src/ast.ts +0 -37
- package/src/emit.ts +0 -609
- package/src/emitter/luau-codegen.ts +0 -187
- package/src/emitter/translators.ts +0 -168
- package/src/headers.ts +0 -233
- package/src/layout.ts +0 -114
- package/src/lex.ts +0 -158
- package/src/parse.ts +0 -729
- package/src/parser/collector.ts +0 -148
- package/src/parser/index.ts +0 -27
- package/src/tree-sitter-cpp.d.ts +0 -4
- package/src/understand.ts +0 -322
- package/templates/game/src/client/init.client.cpp +0 -6
- package/templates/game/src/server/leaderstats.server.cpp +0 -29
- package/templates/game/src/shared/config.cpp +0 -5
- package/templates/game/src/shared/config.h +0 -5
- /package/include/{cluaupp/generated/enums.hpp → clpp/generated/enums.clh} +0 -0
- /package/include/{cluaupp/libs/math.hpp → clpp/libs/math.clh} +0 -0
- /package/include/{cluaupp/libs/twinkle.hpp → clpp/libs/twinkle.clh} +0 -0
- /package/include/{cluaupp/libs/vfx.hpp → clpp/libs/vfx.clh} +0 -0
package/docs/examples/combat.md
CHANGED
|
@@ -3,237 +3,29 @@ title: Combat (server validation)
|
|
|
3
3
|
sidebar_position: 4
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Combat
|
|
6
|
+
# Combat
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Live source: [`examples/game/src/server/combat.server.clpp`](../../examples/game/src/server/combat.server.clpp). Language: [CL++](https://kartzrbx.github.io/CLPP/).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This sample uses exclusive CL++:
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
- `guard` / `match` instead of nested null checks
|
|
13
|
+
- `signal<Player*, int> OnHit` and `OnHit~>Connect` / `OnHit::Fire`
|
|
14
|
+
- `observable int combo`
|
|
15
|
+
- `[[server]]` on `WatchWorkspace`
|
|
16
|
+
- `spawn { task::wait(1); … }`
|
|
13
17
|
|
|
14
|
-
`
|
|
18
|
+
The client never decides damage. Touched parts fire `OnHit`; the server prints combo and destroys the part.
|
|
15
19
|
|
|
16
|
-
```
|
|
17
|
-
#
|
|
20
|
+
```clpp
|
|
21
|
+
#include <clpp/roblox.clh>
|
|
22
|
+
#include <clpp/libs/janitor.clh>
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
struct CombatServer {
|
|
25
|
+
Janitor* janitor;
|
|
26
|
+
signal<Player*, int> OnHit;
|
|
27
|
+
void PlayerEntered(Player* player);
|
|
28
|
+
void BindPart(BasePart* part);
|
|
29
|
+
void WatchWorkspace();
|
|
30
|
+
};
|
|
23
31
|
```
|
|
24
|
-
|
|
25
|
-
Keep numbers in a header. Both server and client can include range for FX; **only the server** applies `TakeDamage`.
|
|
26
|
-
|
|
27
|
-
## Server — `CombatServer.server.cpp`
|
|
28
|
-
|
|
29
|
-
```cpp
|
|
30
|
-
#include <cluaupp/roblox.hpp>
|
|
31
|
-
#include <cluaupp/libs/janitor.hpp>
|
|
32
|
-
#include <cluaupp/libs/net.hpp>
|
|
33
|
-
#include <cluaupp/libs/dataservice.hpp>
|
|
34
|
-
#include "../../../shared/constants/CombatConfig.hpp"
|
|
35
|
-
|
|
36
|
-
Players* Players = GetService<Players>();
|
|
37
|
-
Janitor* janitor = new Janitor();
|
|
38
|
-
NetEvent* Attack = Net::Event("Attack");
|
|
39
|
-
|
|
40
|
-
BasePart* RootPart(Model* character) {
|
|
41
|
-
if (character == nullptr) {
|
|
42
|
-
return nullptr;
|
|
43
|
-
}
|
|
44
|
-
return character->FindFirstChild("HumanoidRootPart");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
Humanoid* HumanoidOf(Model* character) {
|
|
48
|
-
if (character == nullptr) {
|
|
49
|
-
return nullptr;
|
|
50
|
-
}
|
|
51
|
-
return character->FindFirstChildOfClass("Humanoid");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
bool InRange(Model* a, Model* b, double maxRange) {
|
|
55
|
-
BasePart* rootA = RootPart(a);
|
|
56
|
-
BasePart* rootB = RootPart(b);
|
|
57
|
-
if (rootA == nullptr) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
if (rootB == nullptr) {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
Vector3 delta = rootA->Position - rootB->Position;
|
|
64
|
-
if (delta.Magnitude > maxRange) {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
bool OnCooldown(Player* attacker) {
|
|
71
|
-
NumberValue* last = attacker->FindFirstChild("LastAttackAt");
|
|
72
|
-
if (last == nullptr) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
if (tick() - last->Value < ATTACK_COOLDOWN) {
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
void MarkAttack(Player* attacker) {
|
|
82
|
-
NumberValue* last = attacker->FindFirstChild("LastAttackAt");
|
|
83
|
-
if (last == nullptr) {
|
|
84
|
-
last = new NumberValue(attacker);
|
|
85
|
-
last->Name = "LastAttackAt";
|
|
86
|
-
}
|
|
87
|
-
last->Value = tick();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
void RewardKill(Player* attacker) {
|
|
91
|
-
Data* data = DataService::Server.Get(attacker);
|
|
92
|
-
if (data == nullptr) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
int money = data->Get(DataService::Server.Paths.Currencies.Money);
|
|
96
|
-
data->Set(DataService::Server.Paths.Currencies.Money, money + KILL_REWARD);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
void OnAttack(Player* attacker, int targetUserId) {
|
|
100
|
-
if (attacker == nullptr) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (targetUserId < 1) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (OnCooldown(attacker)) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
Player* target = Players->GetPlayerByUserId(targetUserId);
|
|
111
|
-
if (target == nullptr) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (target == attacker) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
Model* attackerChar = attacker->Character;
|
|
119
|
-
Model* targetChar = target->Character;
|
|
120
|
-
Humanoid* attackerHum = HumanoidOf(attackerChar);
|
|
121
|
-
Humanoid* targetHum = HumanoidOf(targetChar);
|
|
122
|
-
if (attackerHum == nullptr) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
if (targetHum == nullptr) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (attackerHum->Health <= 0) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
if (targetHum->Health <= 0) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
if (InRange(attackerChar, targetChar, ATTACK_RANGE) == false) {
|
|
135
|
-
cout::ping << attacker->Name << " out of range" << endl;
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
MarkAttack(attacker);
|
|
140
|
-
double healthBefore = targetHum->Health;
|
|
141
|
-
targetHum->TakeDamage(ATTACK_DAMAGE);
|
|
142
|
-
if (healthBefore > 0) {
|
|
143
|
-
if (targetHum->Health <= 0) {
|
|
144
|
-
RewardKill(attacker);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
void init() {
|
|
150
|
-
Attack->On(OnAttack);
|
|
151
|
-
janitor->Add(Attack);
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Client — `CombatClient.client.cpp`
|
|
156
|
-
|
|
157
|
-
The LocalScript only picks a target and fires. It does **not** pass `ATTACK_DAMAGE`.
|
|
158
|
-
|
|
159
|
-
```cpp
|
|
160
|
-
#include <cluaupp/roblox.hpp>
|
|
161
|
-
#include <cluaupp/libs/janitor.hpp>
|
|
162
|
-
#include <cluaupp/libs/net.hpp>
|
|
163
|
-
|
|
164
|
-
Players* Players = GetService<Players>();
|
|
165
|
-
UserInputService* UserInput = GetService<UserInputService>();
|
|
166
|
-
Janitor* janitor = new Janitor();
|
|
167
|
-
NetEvent* Attack = Net::Event("Attack");
|
|
168
|
-
|
|
169
|
-
Player* PlayerFromPart(Instance* part) {
|
|
170
|
-
if (part == nullptr) {
|
|
171
|
-
return nullptr;
|
|
172
|
-
}
|
|
173
|
-
Instance* model = part->FindFirstAncestorOfClass("Model");
|
|
174
|
-
if (model == nullptr) {
|
|
175
|
-
return nullptr;
|
|
176
|
-
}
|
|
177
|
-
Player* fromModel = Players->GetPlayerFromCharacter(model);
|
|
178
|
-
if (fromModel != nullptr) {
|
|
179
|
-
return fromModel;
|
|
180
|
-
}
|
|
181
|
-
Instance* outer = model->FindFirstAncestorOfClass("Model");
|
|
182
|
-
if (outer == nullptr) {
|
|
183
|
-
return nullptr;
|
|
184
|
-
}
|
|
185
|
-
return Players->GetPlayerFromCharacter(outer);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
void OnInputBegan(InputObject* input, bool gameProcessed) {
|
|
189
|
-
if (gameProcessed) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (input->UserInputType != Enum::UserInputType::MouseButton1) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
Player* localPlayer = Players->LocalPlayer;
|
|
196
|
-
if (localPlayer == nullptr) {
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
Mouse* mouse = localPlayer->GetMouse();
|
|
200
|
-
if (mouse == nullptr) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
Player* target = PlayerFromPart(mouse->Target);
|
|
204
|
-
if (target == nullptr) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
if (target == localPlayer) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
Attack->FireServer(target->UserId);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
void init() {
|
|
214
|
-
janitor->Add(UserInput->InputBegan.Connect(OnInputBegan));
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## What the server rejects
|
|
219
|
-
|
|
220
|
-
| Client cheat | Server check |
|
|
221
|
-
| --- | --- |
|
|
222
|
-
| `FireServer(99999)` damage | Damage is `ATTACK_DAMAGE` in the header — not an argument |
|
|
223
|
-
| Hit a player across the map | `delta.Magnitude > ATTACK_RANGE` |
|
|
224
|
-
| Spam click | `LastAttackAt` + `ATTACK_COOLDOWN` |
|
|
225
|
-
| Target userId `0` / self | `targetUserId < 1`, `target == attacker` |
|
|
226
|
-
| Hit a dead / missing character | Humanoid nil or `Health <= 0` |
|
|
227
|
-
| Fire before spawn | `Character` / `HumanoidRootPart` missing |
|
|
228
|
-
|
|
229
|
-
`Net::Event("Attack")` must be the **same string** on both sides. Treat that name as public protocol.
|
|
230
|
-
|
|
231
|
-
## Cooldown storage
|
|
232
|
-
|
|
233
|
-
`LastAttackAt` is a `NumberValue` on the Player: session-only, no DataStore. Do not persist combat cadence. For anti-exploit that must survive respawn, use DataService `SetTransient` on a path **you** added to the Template — still not a library field.
|
|
234
|
-
|
|
235
|
-
## No lambdas
|
|
236
|
-
|
|
237
|
-
`Attack->On(OnAttack)` needs a named function. The first argument of a server `On` is the `Player` who fired.
|
|
238
|
-
|
|
239
|
-
See [Net](../libraries/net.md) and [Safety](../cpp-safety.md).
|
package/docs/examples/hud.md
CHANGED
|
@@ -5,92 +5,24 @@ sidebar_position: 6
|
|
|
5
5
|
|
|
6
6
|
# HUD
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Live source: [`examples/game/src/client/hud.client.clpp`](../../examples/game/src/client/hud.client.clpp). Fusion API: [CL++](https://kartzrbx.github.io/CLPP/).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Client-only (`[[client]]`). `Fusion:scoped` / `Fusion:Value` / `Fusion:Computed` / `Fusion:New` build a coins label. `guard` fails if `LocalPlayer` is missing.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
```cpp
|
|
17
|
-
#include <cluaupp/roblox.hpp>
|
|
18
|
-
#include <cluaupp/libs/janitor.hpp>
|
|
19
|
-
#include <cluaupp/libs/dataservice.hpp>
|
|
20
|
-
#include <cluaupp/libs/formatnumber.hpp>
|
|
21
|
-
#include <cluaupp/libs/twinkle.hpp>
|
|
22
|
-
|
|
23
|
-
Players* Players = GetService<Players>();
|
|
24
|
-
Janitor* janitor = new Janitor();
|
|
25
|
-
|
|
26
|
-
TextLabel* FindLabel(PlayerGui* playerGui, string name) {
|
|
27
|
-
if (playerGui == nullptr) {
|
|
28
|
-
return nullptr;
|
|
29
|
-
}
|
|
30
|
-
Instance* gui = playerGui->FindFirstChild("Hud");
|
|
31
|
-
if (gui == nullptr) {
|
|
32
|
-
return nullptr;
|
|
33
|
-
}
|
|
34
|
-
return gui->FindFirstChild(name);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
void Render(Data* data, TextLabel* moneyLabel, TextLabel* levelLabel) {
|
|
38
|
-
if (data == nullptr) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
int money = data->Get(DataService::Client.Paths.Currencies.Money);
|
|
42
|
-
int level = data->Get(DataService::Client.Paths.Currencies.Level);
|
|
43
|
-
if (moneyLabel != nullptr) {
|
|
44
|
-
moneyLabel->Text = FormatNumber::Abbreviate(money);
|
|
45
|
-
}
|
|
46
|
-
if (levelLabel != nullptr) {
|
|
47
|
-
levelLabel->Text = FormatNumber::Comma(level);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
void OnCurrenciesChanged() {
|
|
52
|
-
Player* player = Players->LocalPlayer;
|
|
53
|
-
if (player == nullptr) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
PlayerGui* playerGui = player->FindFirstChildOfClass("PlayerGui");
|
|
57
|
-
TextLabel* moneyLabel = FindLabel(playerGui, "MoneyLabel");
|
|
58
|
-
TextLabel* levelLabel = FindLabel(playerGui, "LevelLabel");
|
|
59
|
-
Render(DataService::Client.Get(), moneyLabel, levelLabel);
|
|
60
|
-
}
|
|
12
|
+
```clpp
|
|
13
|
+
#include <clpp/roblox.clh>
|
|
14
|
+
#include <clpp/libs/fusion.clh>
|
|
61
15
|
|
|
16
|
+
[[client]]
|
|
62
17
|
void init() {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
PlayerGui* playerGui = player->FindFirstChildOfClass("PlayerGui");
|
|
68
|
-
if (playerGui == nullptr) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
Data* data = DataService::Client.WaitForData();
|
|
73
|
-
if (data == nullptr) {
|
|
74
|
-
cout::warn << "HUD: profile missing" << endl;
|
|
18
|
+
Players* players = GetService<Players>();
|
|
19
|
+
Player* localPlayer = players.LocalPlayer;
|
|
20
|
+
guard (localPlayer != null) else {
|
|
21
|
+
report("LocalPlayer missing");
|
|
75
22
|
return;
|
|
76
23
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Render(data, moneyLabel, levelLabel);
|
|
81
|
-
|
|
82
|
-
if (moneyLabel != nullptr) {
|
|
83
|
-
Twinkle::Fade(moneyLabel, true);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
janitor->Add(data->GetChangedSignal(DataService::Client.Paths.Currencies).Connect(OnCurrenciesChanged));
|
|
24
|
+
auto scope = Fusion:scoped();
|
|
25
|
+
auto coins = Fusion:Value(scope, 0);
|
|
26
|
+
coins(100);
|
|
87
27
|
}
|
|
88
28
|
```
|
|
89
|
-
|
|
90
|
-
## Rules
|
|
91
|
-
|
|
92
|
-
- Call `DataService::Client.Init()` in [Data boot](data-boot.md) first. Script order in StarterPlayerScripts is not a contract — `WaitForData` yields until the profile exists.
|
|
93
|
-
- Do not `data->Set` Money from the HUD. Display only.
|
|
94
|
-
- `Twinkle::Fade` is optional. See [more libraries](../libraries/more.md).
|
|
95
|
-
|
|
96
|
-
`HudClient.client.cpp` is a LocalScript (`init.client.luau`).
|
package/docs/examples/index.md
CHANGED
|
@@ -5,28 +5,21 @@ sidebar_position: 1
|
|
|
5
5
|
|
|
6
6
|
# Examples
|
|
7
7
|
|
|
8
|
-
High-quality Cluaupp systems you can copy. Each page is a full service
|
|
8
|
+
High-quality Cluaupp systems you can copy. Each page is a full service in **CL++**. Live sample: [`examples/game`](../../examples/game). Language reference: [kartzrbx.github.io/CLPP](https://kartzrbx.github.io/CLPP/).
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
These are **not** dumps of `int main()`. Entry is `void init()`. Types are `struct` + `Class::` methods. Callbacks may be named functions or lambdas. Canonical Leaderstats: [handbook](https://kartzrbx.github.io/Cluaupp/docs/leaderstats.html).
|
|
10
|
+
These are **not** dumps of `int main()`. Entry is `void init()`. Types are `struct` + `Class::` methods. Canonical Leaderstats: [handbook](https://kartzrbx.github.io/Cluaupp/docs/leaderstats.html).
|
|
13
11
|
|
|
14
12
|
## Suggested layout
|
|
15
13
|
|
|
16
14
|
```
|
|
17
15
|
src/
|
|
18
|
-
shared/
|
|
19
|
-
shared/
|
|
20
|
-
shared/
|
|
21
|
-
server/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
client/controllers/combat/CombatClient.client.cpp
|
|
26
|
-
server/services/shop/ShopServer.server.cpp
|
|
27
|
-
client/controllers/shop/ShopClient.client.cpp
|
|
28
|
-
client/controllers/hud/HudClient.client.cpp
|
|
29
|
-
server/services/weapons/SwordServer.server.cpp
|
|
16
|
+
shared/PlayerData.clh
|
|
17
|
+
shared/config.clp
|
|
18
|
+
shared/features.clp
|
|
19
|
+
server/leaderstats.server.clpp
|
|
20
|
+
server/combat.server.clpp
|
|
21
|
+
client/init.client.clpp
|
|
22
|
+
client/hud.client.clpp
|
|
30
23
|
```
|
|
31
24
|
|
|
32
25
|
Boot DataService **once**. Other services `WaitFor` after that.
|
package/docs/getting-started.md
CHANGED
|
@@ -1,43 +1,31 @@
|
|
|
1
1
|
# Getting started
|
|
2
2
|
|
|
3
|
-
Cluaupp
|
|
3
|
+
Cluaupp is the **game toolchain**. [CL++](https://kartzrbx.github.io/CLPP/) is the **language**.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- [Node.js](https://nodejs.org/) 18 or newer
|
|
8
|
-
- [Rojo](https://rojo.space/) **7.7.0**
|
|
9
|
-
-
|
|
8
|
+
- [Rojo](https://rojo.space/) **7.7.0** (`cluaupp init` writes `rokit.toml`)
|
|
9
|
+
- **`clpp` on PATH** from [KartzRbx/CLPP](https://github.com/KartzRbx/CLPP)
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
```bash
|
|
12
|
+
cargo install --path . # inside a CL++ checkout
|
|
13
|
+
clpp install # VS Code / Cursor language pack
|
|
14
|
+
```
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
## Install Cluaupp
|
|
14
17
|
|
|
15
18
|
```bash
|
|
16
19
|
npm install -g cluaupp
|
|
17
20
|
cluaupp --version
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
Or:
|
|
21
24
|
|
|
22
25
|
```bash
|
|
23
26
|
npx cluaupp init my-game
|
|
24
27
|
```
|
|
25
28
|
|
|
26
|
-
As a game dependency:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install --save-dev cluaupp
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
{
|
|
34
|
-
"scripts": {
|
|
35
|
-
"build": "cluaupp build",
|
|
36
|
-
"watch": "cluaupp watch"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
29
|
## First game
|
|
42
30
|
|
|
43
31
|
```bash
|
|
@@ -48,132 +36,27 @@ cluaupp build
|
|
|
48
36
|
rojo serve
|
|
49
37
|
```
|
|
50
38
|
|
|
51
|
-
In Roblox Studio: install the Rojo plugin and connect to `localhost:34872` (default port).
|
|
52
|
-
|
|
53
|
-
Generated layout:
|
|
54
|
-
|
|
55
39
|
```
|
|
56
40
|
my-game/
|
|
57
41
|
cluaupp.config.json
|
|
58
|
-
default.project.json
|
|
59
|
-
include/cluaupp/roblox.hpp
|
|
60
|
-
include/cluaupp/libs/
|
|
61
|
-
libs/ ← CluauppLibs (Janitor, Fusion, Cmdr, DataService, …)
|
|
62
|
-
Packages/ ← optional extra Wally
|
|
63
|
-
wally.toml
|
|
42
|
+
default.project.json
|
|
64
43
|
src/
|
|
65
|
-
server/leaderstats.server.
|
|
66
|
-
client/init.client.
|
|
67
|
-
shared/config.
|
|
68
|
-
shared/config.cpp
|
|
44
|
+
server/leaderstats.server.clpp
|
|
45
|
+
client/init.client.clpp
|
|
46
|
+
shared/config.clp
|
|
69
47
|
out/ ← generated Luau (do not edit)
|
|
70
|
-
|
|
71
|
-
client/init.client.luau
|
|
72
|
-
shared/Config.luau
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Datatypes (Vector3, CFrame, UDim2)
|
|
76
|
-
|
|
77
|
-
```cpp
|
|
78
|
-
#include <cluaupp/roblox.hpp>
|
|
79
|
-
|
|
80
|
-
void init() {
|
|
81
|
-
auto* part = new Part(workspace);
|
|
82
|
-
part->Size = Vector3(8, 1, 8);
|
|
83
|
-
part->Position = Vector3(0, 10, 0);
|
|
84
|
-
part->CFrame = CFrame::lookAt(Vector3(0, 10, 0), Vector3(0, 10, -10));
|
|
85
|
-
part->Color = Color3::fromRGB(255, 0, 0);
|
|
86
|
-
part->Material = Enum::Material::Plastic;
|
|
87
|
-
|
|
88
|
-
auto* frame = new Frame();
|
|
89
|
-
frame->Size = UDim2::fromScale(1, 1);
|
|
90
|
-
frame->Position = UDim2(0, 0, 0.5, 0);
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
This becomes `Vector3.new`, `CFrame.lookAt`, `Color3.fromRGB`, `UDim2.fromScale`, `Enum.Material.Plastic`.
|
|
95
|
-
|
|
96
|
-
How to spell engine calls: [Roblox in Cluaupp](https://kartzrbx.github.io/Cluaupp/docs/engine.html). Official members: [create.roblox.com](https://create.roblox.com/docs/reference/engine). The complete subset: [Language reference](https://kartzrbx.github.io/Cluaupp/docs/reference.html).
|
|
97
|
-
|
|
98
|
-
## How to write
|
|
99
|
-
|
|
100
|
-
Every `.cpp` / `.h` / `.hpp` file can start with the IntelliSense header. Angle-bracket includes are ignored. Quoted `#include "config.h"` is inlined into the file.
|
|
101
|
-
|
|
102
|
-
```cpp
|
|
103
|
-
#include <cluaupp/roblox.hpp>
|
|
104
|
-
|
|
105
|
-
void CreateLeaderstats(Player* player) {
|
|
106
|
-
if (player->FindFirstChild("leaderstats") != nullptr) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
auto* leaderstats = new Folder(player);
|
|
111
|
-
leaderstats->Name = "leaderstats";
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
void init() {
|
|
115
|
-
auto* players = GetService<Players>();
|
|
116
|
-
for (auto* player : players->GetPlayers()) {
|
|
117
|
-
CreateLeaderstats(player);
|
|
118
|
-
}
|
|
119
|
-
players->PlayerAdded.Connect(CreateLeaderstats);
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
If a file defines `void init()`, Cluaupp calls `init()` at the end of the `.luau`. Use that in Scripts and LocalScripts.
|
|
124
|
-
|
|
125
|
-
## IntelliSense
|
|
126
|
-
|
|
127
|
-
`cluaupp init` writes clangd config and installs LLVM `clang++` plus the clangd editor extension when missing. Then reload the window. Completion is clangd; Cluaupp does not index C++ itself.
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
cluaupp intellisense
|
|
48
|
+
libs/ ← CluauppLibs
|
|
131
49
|
```
|
|
132
50
|
|
|
133
|
-
|
|
51
|
+
## Tiny program
|
|
134
52
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
## Watch
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
cluaupp watch
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Saving a `.cpp`, `.h`, or `.hpp` under `src/` rebuilds the project. Keep Rojo running at the same time.
|
|
144
|
-
|
|
145
|
-
## Libraries
|
|
146
|
-
|
|
147
|
-
`cluaupp build` copies runtime modules to `libs/` (Rojo: `ReplicatedStorage.CluauppLibs`). Include a header and the compiler injects `require`.
|
|
148
|
-
|
|
149
|
-
```cpp
|
|
150
|
-
#include <cluaupp/libs/janitor.hpp>
|
|
151
|
-
#include <cluaupp/libs/net.hpp>
|
|
53
|
+
```clpp
|
|
54
|
+
#include <clpp/roblox.clh>
|
|
152
55
|
|
|
153
56
|
void init() {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
janitor->Add(coins);
|
|
57
|
+
Players* players = GetService<Players>();
|
|
58
|
+
post("online: " .: players::GetPlayers());
|
|
157
59
|
}
|
|
158
60
|
```
|
|
159
61
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
See [Libraries](libraries/index.md), [OOP](oop/index.md), [types](cpp-types.md), [safety](cpp-safety.md).
|
|
163
|
-
|
|
164
|
-
## Next
|
|
165
|
-
|
|
166
|
-
Language handbook (GitHub Pages): **[Docs](https://kartzrbx.github.io/Cluaupp/docs/)** — [every construct](https://kartzrbx.github.io/Cluaupp/docs/reference.html).
|
|
167
|
-
|
|
168
|
-
- [C++ → Luau syntax](syntax.md)
|
|
169
|
-
- [print and cout](print-cout.md)
|
|
170
|
-
- [C++ types](cpp-types.md)
|
|
171
|
-
- [const](cpp-const.md)
|
|
172
|
-
- [Safety](cpp-safety.md)
|
|
173
|
-
- [Organization](cpp-organization.md)
|
|
174
|
-
- [Architecture](architecture.md)
|
|
175
|
-
- [OOP structure](oop/index.md)
|
|
176
|
-
- [Libraries](libraries/index.md)
|
|
177
|
-
- [Examples](examples/index.md)
|
|
178
|
-
- [Roblox API](roblox-api.md)
|
|
179
|
-
- [CLI](cli.md)
|
|
62
|
+
Language course and reference: [kartzrbx.github.io/CLPP](https://kartzrbx.github.io/CLPP/). Migrating `.cpp`: [migration](migration.md).
|
package/docs/intellisense.md
CHANGED
|
@@ -1,48 +1,12 @@
|
|
|
1
1
|
# IntelliSense
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
`cluaupp init` / `cluaupp intellisense` install:
|
|
6
|
-
|
|
7
|
-
1. [clangd](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd) (`llvm-vs-code-extensions.vscode-clangd`)
|
|
8
|
-
2. LLVM `clang++` when missing (Windows: `winget install --id LLVM.LLVM -e`)
|
|
9
|
-
3. `.clangd`, `compile_flags.txt`, and `compile_commands.json` so clangd finds `include/`
|
|
10
|
-
4. Forced include of `include/cluaupp/roblox.hpp` so `GetService`, `Player`, `Janitor` complete from the real C++ stubs
|
|
11
|
-
|
|
12
|
-
Tree-sitter is the **compiler** frontend (collect → emit Luau). It is not an editor language server. A homemade tokenizer in the CLI would fight clangd — that path is gone.
|
|
13
|
-
|
|
14
|
-
Microsoft `ms-vscode.cpptools` is **not** used and is **not licensed for Cursor**. Two C++ engines in the same window fight; Cluaupp recommends only clangd and marks cpptools as unwanted.
|
|
15
|
-
|
|
16
|
-
`cluaupp lsp` only publishes **subset parse errors** (code that clangd may accept as C++ but Cluaupp will not transpile).
|
|
17
|
-
|
|
18
|
-
## Headers clangd must see
|
|
19
|
-
|
|
20
|
-
`#include <cluaupp/roblox.hpp>` resolves only if `-Iinclude` is on the clangd compile flags. That maps to `include/cluaupp/roblox.hpp`. Angle-bracket includes are ignored by the transpiler.
|
|
21
|
-
|
|
22
|
-
`cluaupp init` / `build` / `watch` / `intellisense` rewrite:
|
|
23
|
-
|
|
24
|
-
- `-Iinclude` and `-Isrc`
|
|
25
|
-
- `-include include/cluaupp/roblox.hpp`
|
|
26
|
-
- one `compile_commands.json` entry per file under `src/`
|
|
27
|
-
|
|
28
|
-
## Install
|
|
3
|
+
CL++ highlighting, completion, and diagnostics come from **`clpp install`** ([KartzRbx/CLPP](https://github.com/KartzRbx/CLPP) language pack). Cluaupp does not ship clangd or a C++ engine.
|
|
29
4
|
|
|
30
5
|
```bash
|
|
31
|
-
|
|
6
|
+
clpp install
|
|
7
|
+
cluaupp intellisense # writes files.associations for .clpp / .clp / .clh
|
|
32
8
|
```
|
|
33
9
|
|
|
34
|
-
Reload
|
|
35
|
-
|
|
36
|
-
`cluaupp build` / `watch` only refresh `compile_commands.json` (no download). They never keep deleted files in the compilation database.
|
|
37
|
-
|
|
38
|
-
## Config that ships
|
|
39
|
-
|
|
40
|
-
| File | Role |
|
|
41
|
-
| --- | --- |
|
|
42
|
-
| `.vscode/settings.json` | `clangd.enable: true`, `--compile-commands-dir` |
|
|
43
|
-
| `.vscode/extensions.json` | recommends `llvm-vs-code-extensions.vscode-clangd`; marks `ms-vscode.cpptools` unwanted |
|
|
44
|
-
| `.clangd` | C++20, `-Iinclude`, skip `out/` and `libs/` |
|
|
45
|
-
| `compile_flags.txt` | fallback flags if a file is not yet in `compile_commands.json` |
|
|
46
|
-
| `compile_commands.json` | one entry per `src/` file |
|
|
10
|
+
Reload the editor. Language id is **`clpp`**, not `cpp`.
|
|
47
11
|
|
|
48
|
-
|
|
12
|
+
`cluaupp lsp` can surface `clpp` compile errors over stdio; prefer the official CL++ extension for day-to-day editing.
|