cluaupp 0.1.2 → 0.1.4
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 +20 -1
- package/README.md +5 -8
- package/docs/README.md +13 -10
- package/docs/architecture.md +18 -11
- package/docs/cli.md +2 -2
- package/docs/config.md +1 -1
- package/docs/cpp-advanced.md +10 -6
- package/docs/cpp-organization.md +3 -1
- 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 +12 -6
- package/docs/intellisense.md +31 -0
- package/docs/intro.md +2 -2
- 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 +49 -0
- package/docs/oop/index.md +22 -0
- package/docs/oop/modules.md +86 -0
- package/docs/oop/services.md +83 -0
- package/docs/print-cout.md +91 -0
- package/docs/syntax.md +59 -5
- 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 +108 -48
- package/src/cli.js +85 -10
- package/src/client/init.client.cpp +5 -0
- package/src/compile.js +20 -4
- package/src/editor-install.js +218 -0
- package/src/emit.js +320 -8
- package/src/intellisense.js +1368 -0
- package/src/layout.js +129 -0
- package/src/lex.js +17 -9
- package/src/libs.js +95 -16
- package/src/lsp.js +227 -0
- package/src/parse.js +187 -6
- package/src/preprocess.js +71 -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 +64 -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/compile_flags.txt +2 -0
- package/docs/libraries.md +0 -80
|
@@ -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++.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: File tags
|
|
3
|
+
sidebar_position: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# File tags
|
|
7
|
+
|
|
8
|
+
The **filename** decides the Roblox instance. This is the same key idea as roblox-ts (`*.server.ts` → Script).
|
|
9
|
+
|
|
10
|
+
| Source | Instance | RunContext |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `LeaderstatsServer.server.cpp` | **Script** | **Server** |
|
|
13
|
+
| `DataBoot.client.cpp` | **LocalScript** | Client |
|
|
14
|
+
| `Tools.plugin.cpp` | **Script** | Plugin |
|
|
15
|
+
| `Boot.legacy.cpp` | Script | **Legacy** |
|
|
16
|
+
| `Boot.legacy.server.cpp` | Script | **Legacy** |
|
|
17
|
+
| `Boot.legacy.client.cpp` | LocalScript | Legacy |
|
|
18
|
+
| `Damage.cpp` (no tag) | **ModuleScript** | — |
|
|
19
|
+
|
|
20
|
+
## Server is not Legacy
|
|
21
|
+
|
|
22
|
+
`.server.cpp` is **not** `init.server.luau`. Rojo maps `*.server.luau` to a Script with RunContext **Legacy**. Cluaupp emits:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
out/server/LeaderstatsServer/
|
|
26
|
+
init.luau
|
|
27
|
+
init.meta.json -- className Script, RunContext Server
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`.legacy.server.cpp` is the 1:1 dump that *does* become Legacy.
|
|
31
|
+
|
|
32
|
+
`.client.cpp` stays `init.client.luau` (LocalScript). Do not add `init.meta.json` on the client boot.
|
|
33
|
+
|
|
34
|
+
## Where files live
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
src/server/.../*.server.cpp → out/server (ServerScriptService)
|
|
38
|
+
src/client/.../*.client.cpp → out/client (StarterPlayerScripts)
|
|
39
|
+
src/shared/.../*.cpp → out/shared (ReplicatedStorage)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Name the **system**, not `init.server.cpp`. `LeaderstatsServer.server.cpp` and `DataBoot.server.cpp` are two services.
|
|
43
|
+
|
|
44
|
+
## Skip the planner
|
|
45
|
+
|
|
46
|
+
- `"architecture": false` in `cluaupp.config.json`, or
|
|
47
|
+
- `.legacy.server.cpp` / `.legacy.client.cpp` per file
|
|
48
|
+
|
|
49
|
+
Use legacy only when you want one Luau file with no Main / Controller split.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: OOP structure
|
|
3
|
+
sidebar_position: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OOP structure
|
|
7
|
+
|
|
8
|
+
The **live site** (not just these markdown files) is GitHub Pages:
|
|
9
|
+
|
|
10
|
+
- [Learn → OOP structure](https://kartzrbx.github.io/Cluaupp/learn/index.html)
|
|
11
|
+
- [Guide → OOP](https://kartzrbx.github.io/Cluaupp/guide/oop.html)
|
|
12
|
+
- [Examples](https://kartzrbx.github.io/Cluaupp/guide/examples.html)
|
|
13
|
+
|
|
14
|
+
Cluaupp does **not** compile custom C++ `class` types yet. “OOP” here is how you **lay out systems** so Studio gets services, modules, and lifecycle — the same idea as roblox-ts filename keys + Flamework `@Service`, without decorators.
|
|
15
|
+
|
|
16
|
+
| Page | What you learn |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| [File tags](file-tags.md) | `.server` / `.client` / `.plugin` / `.legacy` / untagged |
|
|
19
|
+
| [Services](services.md) | One `.server.cpp` → Main, Controller, Start / Stop |
|
|
20
|
+
| [Modules](modules.md) | Untagged files, structs, named functions as methods |
|
|
21
|
+
|
|
22
|
+
Planner details: [Architecture](../architecture.md). Folder layout: [Organization](../cpp-organization.md). Full services: [Examples](../examples/index.md).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Modules and structs
|
|
3
|
+
sidebar_position: 4
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Modules and structs
|
|
7
|
+
|
|
8
|
+
Use this when you want a **reusable object** without a tagged Script.
|
|
9
|
+
|
|
10
|
+
## Untagged `.cpp` = ModuleScript
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
src/shared/util/Coins.cpp
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```cpp
|
|
17
|
+
#include <cluaupp/roblox.hpp>
|
|
18
|
+
|
|
19
|
+
int DoubleCoins(int coins) {
|
|
20
|
+
return coins;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
out/shared/util/Coins.luau -- ModuleScript, exported functions
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Shared **data and constants** belong in headers (`#include "TemplateData.hpp"`) — they are inlined. Untagged `.cpp` is for a ModuleScript other Luau can `require`. Prefer headers for data and tagged `.server.cpp` / `.client.cpp` for behavior.
|
|
29
|
+
|
|
30
|
+
## Structs = data, not classes
|
|
31
|
+
|
|
32
|
+
The subset allows structs for IntelliSense and designated initializers (tables):
|
|
33
|
+
|
|
34
|
+
```cpp
|
|
35
|
+
struct TemplateData {
|
|
36
|
+
struct Currencies {
|
|
37
|
+
int Money = 0;
|
|
38
|
+
int Level = 1;
|
|
39
|
+
} Currencies;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
TemplateData playerData = TemplateData {};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
That is your “class fields”. Methods are **named functions** next to them (`EnsureStat`, `ApplyCurrencies`). Cluaupp does not emit `function TemplateData:GetMoney()`.
|
|
46
|
+
|
|
47
|
+
## Methods as functions
|
|
48
|
+
|
|
49
|
+
```cpp
|
|
50
|
+
void EnsureStat(Folder* folder, string name, int value) {
|
|
51
|
+
auto* stat = folder->FindFirstChild(name);
|
|
52
|
+
if (stat == nullptr) {
|
|
53
|
+
cout::print << "EnsureStat: " << name << " not found" << endl;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Pass the instance in (`folder`, `player`). That is composition: the Folder is the object, the function is the method.
|
|
60
|
+
|
|
61
|
+
## Janitor as the destructor
|
|
62
|
+
|
|
63
|
+
There is no C++ destructor. Pair “construct” with a Janitor:
|
|
64
|
+
|
|
65
|
+
```cpp
|
|
66
|
+
auto* janitor = new Janitor();
|
|
67
|
+
janitor->LinkToInstance(player);
|
|
68
|
+
janitor->Add(player->AncestryChanged.Connect(OnAncestry));
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
When the player leaves, `LinkToInstance` runs `Cleanup`. That is RAII for Roblox.
|
|
72
|
+
|
|
73
|
+
## Start / Stop
|
|
74
|
+
|
|
75
|
+
On generated services, `Main.Start` / `Main.Stop` are the constructor / destructor of the **system**. Put connections in Start (or in `init()` / `PlayersManager`). Do not leak `Connect` without a Janitor.
|
|
76
|
+
|
|
77
|
+
## What not to write
|
|
78
|
+
|
|
79
|
+
```cpp
|
|
80
|
+
class Shop {
|
|
81
|
+
int price;
|
|
82
|
+
void Buy(Player* player);
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Custom classes are **not supported**. Split into a struct (fields) + functions (methods) + a `.server.cpp` or untagged module (lifetime).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Services
|
|
3
|
+
sidebar_position: 3
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Services
|
|
7
|
+
|
|
8
|
+
Write **one tagged file per system**. Cluaupp reads the AST and emits a PascalCase folder: `Main`, managers, controllers, `*Types`.
|
|
9
|
+
|
|
10
|
+
## Example: leaderstats
|
|
11
|
+
|
|
12
|
+
```cpp
|
|
13
|
+
#include <cluaupp/roblox.hpp>
|
|
14
|
+
#include <cluaupp/libs/janitor.hpp>
|
|
15
|
+
#include <cluaupp/libs/dataservice.hpp>
|
|
16
|
+
|
|
17
|
+
void EnsureStat(Folder* folder, string name, int value) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void ApplyCurrencies(Player* player, Data* data) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void OnCurrenciesChanged() {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void SetupPlayerManager(Player* player) {
|
|
30
|
+
Data* data = DataService::Server.WaitFor(player);
|
|
31
|
+
if (data == nullptr) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
ApplyCurrencies(player, data);
|
|
35
|
+
data->GetChangedSignal(DataService::Server.Paths.Currencies).Connect(OnCurrenciesChanged);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void init() {
|
|
39
|
+
auto* players = GetService<Players>();
|
|
40
|
+
players->PlayerAdded.Connect(SetupPlayerManager);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Typical output:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
out/server/LeaderstatsServer/
|
|
48
|
+
init.luau -- Script, RunContext Server
|
|
49
|
+
init.meta.json
|
|
50
|
+
Main.luau -- Start / Stop
|
|
51
|
+
PlayersManager.luau -- PlayerAdded + Janitor
|
|
52
|
+
DataController.luau -- your WaitFor / GetChangedSignal
|
|
53
|
+
CacheController.luau -- if you create IntValue folders
|
|
54
|
+
LeaderstatsServerTypes.luau
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Your functions stay in the matching controller. The planner does not drop `SetupPlayerManager` because `init` still calls it.
|
|
58
|
+
|
|
59
|
+
## Lifecycle
|
|
60
|
+
|
|
61
|
+
Generated `Main` exposes `Start` / `Stop`. Managers own a Janitor. `Stop` cleans connections.
|
|
62
|
+
|
|
63
|
+
You do not write `class LeaderstatsServer` — name the **file** `LeaderstatsServer.server.cpp` and keep **functions** as the public API.
|
|
64
|
+
|
|
65
|
+
## Boot vs gameplay
|
|
66
|
+
|
|
67
|
+
Keep DataService `Init` in `DataBoot.server.cpp` / `DataBoot.client.cpp`. Keep leaderstats / combat in their own `.server.cpp`. Services `WaitFor` after boot has run.
|
|
68
|
+
|
|
69
|
+
## What becomes which role
|
|
70
|
+
|
|
71
|
+
| Your C++ | Generated role |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `PlayerAdded`, `GetPlayers` | `PlayersManager` |
|
|
74
|
+
| `Folder` + `IntValue` | `CacheController` |
|
|
75
|
+
| `DataService`, `GetChangedSignal` | `DataController` |
|
|
76
|
+
| `TakeDamage`, `Humanoid` | `CombatController` |
|
|
77
|
+
| `Net::Event` | `NetController` |
|
|
78
|
+
| `UserInputService` | `InputController` |
|
|
79
|
+
| wiring | `Main.Start` / `Main.Stop` |
|
|
80
|
+
|
|
81
|
+
A tiny `print` in `init.client.cpp` stays a single LocalScript. The planner does not invent Managers for hello-world.
|
|
82
|
+
|
|
83
|
+
Copy-paste: [Examples](../examples/index.md).
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: print and cout
|
|
3
|
+
sidebar_position: 8
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# print and cout
|
|
7
|
+
|
|
8
|
+
Cluaupp has no `<iostream>`. Logging is Roblox `print` / `warn` / `error`. You can still write C++-style `cout` / `cerr` / `endl` — the compiler flattens them.
|
|
9
|
+
|
|
10
|
+
## Globals
|
|
11
|
+
|
|
12
|
+
```cpp
|
|
13
|
+
print("ok");
|
|
14
|
+
warn("careful");
|
|
15
|
+
error("fail");
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```luau
|
|
19
|
+
print("ok")
|
|
20
|
+
warn("careful")
|
|
21
|
+
error("fail")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`print` in C++ takes a string (and chained `cout` pieces). Do not expect full C++ `std::cout` overloads.
|
|
25
|
+
|
|
26
|
+
## Stream: `cout << … << endl`
|
|
27
|
+
|
|
28
|
+
Each `<<` is another argument. `endl` ends the statement (no extra `"\n"`).
|
|
29
|
+
|
|
30
|
+
```cpp
|
|
31
|
+
cout << "EnsureStat: " << name << " not found" << endl;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```luau
|
|
35
|
+
print("EnsureStat: ", name, " not found")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`cerr` is the same chain, emitted as `warn`:
|
|
39
|
+
|
|
40
|
+
```cpp
|
|
41
|
+
cerr << "failed to load " << player->Name << endl;
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```luau
|
|
45
|
+
warn("failed to load ", player.Name)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Levels: `cout::print` / `warn` / `error` / `ping`
|
|
49
|
+
|
|
50
|
+
Use `::` to pick the Roblox function. The stream still concatenates with `<<`.
|
|
51
|
+
|
|
52
|
+
```cpp
|
|
53
|
+
cout::print << "EnsureStat test: " << name << " not found" << endl;
|
|
54
|
+
cout::warn << "missing folder for " << player->Name << endl;
|
|
55
|
+
cout::error << "profile failed" << endl;
|
|
56
|
+
cout::ping << "here" << endl;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```luau
|
|
60
|
+
print("EnsureStat test: ", name, " not found")
|
|
61
|
+
warn("missing folder for ", player.Name)
|
|
62
|
+
error("profile failed")
|
|
63
|
+
print("here")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| C++ | Luau |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `cout << … << endl` | `print(…)` |
|
|
69
|
+
| `cout::print << … << endl` | `print(…)` |
|
|
70
|
+
| `cout::warn << … << endl` | `warn(…)` |
|
|
71
|
+
| `cout::error << … << endl` | `error(…)` |
|
|
72
|
+
| `cout::ping << … << endl` | `print(…)` |
|
|
73
|
+
| `cerr << … << endl` | `warn(…)` |
|
|
74
|
+
|
|
75
|
+
`cout::ping` is a debug alias of `print` (no extra Studio highlight).
|
|
76
|
+
|
|
77
|
+
## Call form (no `<<`)
|
|
78
|
+
|
|
79
|
+
```cpp
|
|
80
|
+
cout::print("ok");
|
|
81
|
+
cout::warn("careful");
|
|
82
|
+
cout::error("fail");
|
|
83
|
+
cout::ping("here");
|
|
84
|
+
cout::endl();
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`cout::endl()` is a no-op in Luau (flush is already the statement). Prefer `<< endl` on a stream.
|
|
88
|
+
|
|
89
|
+
## IntelliSense
|
|
90
|
+
|
|
91
|
+
`struct cout` / `cerr` and `endl` live in `<cluaupp/roblox.hpp>`. Include that header so clangd knows `cout::print` and `operator<<`.
|