rowork 0.1.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/LICENSE +21 -0
- package/README.md +95 -0
- package/bin/rowork.js +18 -0
- package/dashboard/app.css +234 -0
- package/dashboard/app.js +117 -0
- package/dashboard/index.html +67 -0
- package/dist/cli/errors.d.ts +15 -0
- package/dist/cli/errors.js +18 -0
- package/dist/cli/program.d.ts +19 -0
- package/dist/cli/program.js +59 -0
- package/dist/cli/registry.d.ts +37 -0
- package/dist/cli/registry.js +61 -0
- package/dist/commands/add.d.ts +8 -0
- package/dist/commands/add.js +77 -0
- package/dist/commands/assets-setup.d.ts +18 -0
- package/dist/commands/assets-setup.js +136 -0
- package/dist/commands/assets.d.ts +2 -0
- package/dist/commands/assets.js +153 -0
- package/dist/commands/console.d.ts +4 -0
- package/dist/commands/console.js +141 -0
- package/dist/commands/dashboard.d.ts +2 -0
- package/dist/commands/dashboard.js +50 -0
- package/dist/commands/dev-background.d.ts +3 -0
- package/dist/commands/dev-background.js +87 -0
- package/dist/commands/dev.d.ts +2 -0
- package/dist/commands/dev.js +270 -0
- package/dist/commands/eject.d.ts +2 -0
- package/dist/commands/eject.js +136 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.js +54 -0
- package/dist/commands/info.d.ts +3 -0
- package/dist/commands/info.js +50 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +55 -0
- package/dist/commands/links.d.ts +32 -0
- package/dist/commands/links.js +152 -0
- package/dist/commands/make-event.d.ts +2 -0
- package/dist/commands/make-event.js +160 -0
- package/dist/commands/make-menu.d.ts +3 -0
- package/dist/commands/make-menu.js +36 -0
- package/dist/commands/make-stat.d.ts +2 -0
- package/dist/commands/make-stat.js +199 -0
- package/dist/commands/make-tool.d.ts +2 -0
- package/dist/commands/make-tool.js +124 -0
- package/dist/commands/make-ui.d.ts +3 -0
- package/dist/commands/make-ui.js +199 -0
- package/dist/commands/make.d.ts +21 -0
- package/dist/commands/make.js +181 -0
- package/dist/commands/next-steps.d.ts +5 -0
- package/dist/commands/next-steps.js +18 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +144 -0
- package/dist/commands/studio.d.ts +3 -0
- package/dist/commands/studio.js +45 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +173 -0
- package/dist/commands/wire.d.ts +2 -0
- package/dist/commands/wire.js +34 -0
- package/dist/core/agent-docs.d.ts +23 -0
- package/dist/core/agent-docs.js +151 -0
- package/dist/core/assets.d.ts +96 -0
- package/dist/core/assets.js +268 -0
- package/dist/core/background.d.ts +47 -0
- package/dist/core/background.js +149 -0
- package/dist/core/config.d.ts +9 -0
- package/dist/core/config.js +62 -0
- package/dist/core/exec.d.ts +22 -0
- package/dist/core/exec.js +38 -0
- package/dist/core/format-generated.d.ts +12 -0
- package/dist/core/format-generated.js +28 -0
- package/dist/core/generate.d.ts +37 -0
- package/dist/core/generate.js +94 -0
- package/dist/core/github-release.d.ts +28 -0
- package/dist/core/github-release.js +38 -0
- package/dist/core/info.d.ts +77 -0
- package/dist/core/info.js +65 -0
- package/dist/core/modules.d.ts +32 -0
- package/dist/core/modules.js +265 -0
- package/dist/core/naming.d.ts +6 -0
- package/dist/core/naming.js +26 -0
- package/dist/core/open-cloud.d.ts +58 -0
- package/dist/core/open-cloud.js +170 -0
- package/dist/core/project-index.d.ts +26 -0
- package/dist/core/project-index.js +59 -0
- package/dist/core/rojo-edit.d.ts +18 -0
- package/dist/core/rojo-edit.js +53 -0
- package/dist/core/rokit-installer.d.ts +15 -0
- package/dist/core/rokit-installer.js +77 -0
- package/dist/core/scaffold.d.ts +44 -0
- package/dist/core/scaffold.js +163 -0
- package/dist/core/schema-edit.d.ts +46 -0
- package/dist/core/schema-edit.js +125 -0
- package/dist/core/source-scan.d.ts +24 -0
- package/dist/core/source-scan.js +84 -0
- package/dist/core/studio.d.ts +83 -0
- package/dist/core/studio.js +225 -0
- package/dist/core/toolchain.d.ts +31 -0
- package/dist/core/toolchain.js +98 -0
- package/dist/core/tsconfig-edit.d.ts +11 -0
- package/dist/core/tsconfig-edit.js +47 -0
- package/dist/core/ui-edit.d.ts +31 -0
- package/dist/core/ui-edit.js +89 -0
- package/dist/core/versions.d.ts +24 -0
- package/dist/core/versions.js +67 -0
- package/dist/dashboard/open.d.ts +3 -0
- package/dist/dashboard/open.js +18 -0
- package/dist/dashboard/server.d.ts +28 -0
- package/dist/dashboard/server.js +191 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/main.d.ts +9 -0
- package/dist/main.js +135 -0
- package/dist/modules/format.d.ts +3 -0
- package/dist/modules/format.js +28 -0
- package/dist/modules/index.d.ts +7 -0
- package/dist/modules/index.js +12 -0
- package/dist/modules/integrations.d.ts +8 -0
- package/dist/modules/integrations.js +54 -0
- package/dist/modules/leaderstats.d.ts +3 -0
- package/dist/modules/leaderstats.js +104 -0
- package/dist/modules/lint.d.ts +5 -0
- package/dist/modules/lint.js +43 -0
- package/dist/modules/networking.d.ts +23 -0
- package/dist/modules/networking.js +246 -0
- package/dist/modules/player-data.d.ts +19 -0
- package/dist/modules/player-data.js +176 -0
- package/dist/modules/types.d.ts +96 -0
- package/dist/modules/types.js +2 -0
- package/dist/modules/ui.d.ts +3 -0
- package/dist/modules/ui.js +67 -0
- package/dist/plugins/api.d.ts +127 -0
- package/dist/plugins/api.js +21 -0
- package/dist/plugins/loader.d.ts +20 -0
- package/dist/plugins/loader.js +128 -0
- package/dist/process/log-mux.d.ts +13 -0
- package/dist/process/log-mux.js +31 -0
- package/dist/process/supervisor.d.ts +48 -0
- package/dist/process/supervisor.js +141 -0
- package/dist/process/tree-kill.d.ts +25 -0
- package/dist/process/tree-kill.js +70 -0
- package/dist/templates/engine.d.ts +18 -0
- package/dist/templates/engine.js +54 -0
- package/dist/ui/logger.d.ts +5 -0
- package/dist/ui/logger.js +53 -0
- package/dist/ui/prompt.d.ts +9 -0
- package/dist/ui/prompt.js +24 -0
- package/package.json +69 -0
- package/templates/init/README.md.tmpl +37 -0
- package/templates/init/_gitignore.tmpl +23 -0
- package/templates/init/default.project.json.tmpl +57 -0
- package/templates/init/package.json.tmpl +12 -0
- package/templates/init/rokit.toml.tmpl +5 -0
- package/templates/init/src/client/controllers/ExampleController.ts.tmpl +12 -0
- package/templates/init/src/client/runtime.client.ts.tmpl +6 -0
- package/templates/init/src/server/runtime.server.ts.tmpl +12 -0
- package/templates/init/src/server/services/ExampleService.ts.tmpl +12 -0
- package/templates/init/src/shared/_gitkeep.tmpl +0 -0
- package/templates/init/tsconfig.json.tmpl +28 -0
- package/templates/integrations/data-replication/DataReplicationService.ts.tmpl +33 -0
- package/templates/integrations/data-replication/PlayerDataController.ts.tmpl +40 -0
- package/templates/integrations/data-replication/dataEvents.ts.tmpl +21 -0
- package/templates/make/component.ts.tmpl +8 -0
- package/templates/make/controller.ts.tmpl +6 -0
- package/templates/make/event-handler.ts.tmpl +22 -0
- package/templates/make/screen.tsx.tmpl +35 -0
- package/templates/make/service.ts.tmpl +6 -0
- package/templates/make/stat-service.ts.tmpl +26 -0
- package/templates/make/ui-button.tsx.tmpl +22 -0
- package/templates/make/ui-image.tsx.tmpl +11 -0
- package/templates/make/ui-label.tsx.tmpl +18 -0
- package/templates/make/ui-panel.tsx.tmpl +33 -0
- package/templates/make/ui-story.tsx.tmpl +13 -0
- package/templates/modules/format/prettierignore.tmpl +9 -0
- package/templates/modules/format/prettierrc.json.tmpl +4 -0
- package/templates/modules/leaderstats/LeaderstatsService.ts.tmpl +69 -0
- package/templates/modules/lint/eslint.config.mjs.tmpl +17 -0
- package/templates/modules/networking/client-network.ts.tmpl +9 -0
- package/templates/modules/networking/networking.ts.tmpl +22 -0
- package/templates/modules/networking/rate-limit.ts.tmpl +52 -0
- package/templates/modules/networking/server-network.ts.tmpl +20 -0
- package/templates/modules/player-data/PlayerData.ts.tmpl +15 -0
- package/templates/modules/player-data/PlayerDataService.ts.tmpl +127 -0
- package/templates/modules/ui/App.tsx.tmpl +19 -0
- package/templates/modules/ui/Button.story.tsx.tmpl +13 -0
- package/templates/modules/ui/Button.tsx.tmpl +21 -0
- package/templates/modules/ui/UiController.tsx.tmpl +21 -0
- package/templates/modules/ui/screens/HomeScreen.tsx.tmpl +20 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { OnStart, Service } from "@flamework/core";
|
|
2
|
+
import { createCollection } from "@rbxts/lapis";
|
|
3
|
+
import type { Document } from "@rbxts/lapis";
|
|
4
|
+
import { DEFAULT_PLAYER_DATA, PlayerData } from "{{ dataImport }}";
|
|
5
|
+
|
|
6
|
+
const Players = game.GetService("Players");
|
|
7
|
+
const RunService = game.GetService("RunService");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Saves and loads each player's data, using Lapis (https://github.com/nezuo/lapis)
|
|
11
|
+
* for the hard parts: session locking so two servers never overwrite each other,
|
|
12
|
+
* automatic saving, and saving when the server shuts down.
|
|
13
|
+
*
|
|
14
|
+
* From any service:
|
|
15
|
+
*
|
|
16
|
+
* constructor(private readonly playerData: PlayerDataService) {}
|
|
17
|
+
*
|
|
18
|
+
* const data = this.playerData.get(player);
|
|
19
|
+
* this.playerData.update(player, (data) => {
|
|
20
|
+
* data.coins += 10;
|
|
21
|
+
* return data;
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
const collection = createCollection<PlayerData>("PlayerData", { defaultData: DEFAULT_PLAYER_DATA });
|
|
25
|
+
|
|
26
|
+
type Listener = (player: Player, data: Readonly<PlayerData>) => void;
|
|
27
|
+
|
|
28
|
+
interface Session {
|
|
29
|
+
/** The saved document. Missing when saving is unavailable (see `load`). */
|
|
30
|
+
document?: Document<PlayerData>;
|
|
31
|
+
/** Used instead of the document when saving is unavailable. */
|
|
32
|
+
memory: PlayerData;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Service()
|
|
36
|
+
export class PlayerDataService implements OnStart {
|
|
37
|
+
private readonly sessions = new Map<Player, Session>();
|
|
38
|
+
private readonly loadedListeners = new Array<Listener>();
|
|
39
|
+
private readonly changedListeners = new Array<Listener>();
|
|
40
|
+
|
|
41
|
+
onStart(): void {
|
|
42
|
+
Players.PlayerAdded.Connect((player) => this.load(player));
|
|
43
|
+
Players.PlayerRemoving.Connect((player) => this.unload(player));
|
|
44
|
+
for (const player of Players.GetPlayers()) this.load(player);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The player's data, or undefined while it is still loading. Do not modify it: use `update`. */
|
|
48
|
+
get(player: Player): Readonly<PlayerData> | undefined {
|
|
49
|
+
const session = this.sessions.get(player);
|
|
50
|
+
if (session === undefined) return undefined;
|
|
51
|
+
return session.document !== undefined ? session.document.read() : session.memory;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Changes the player's data. Edit the copy you receive and return it. */
|
|
55
|
+
update(player: Player, change: (data: PlayerData) => PlayerData): void {
|
|
56
|
+
const session = this.sessions.get(player);
|
|
57
|
+
const current = this.get(player);
|
|
58
|
+
if (session === undefined || current === undefined) return;
|
|
59
|
+
|
|
60
|
+
const updated = change({ ...current });
|
|
61
|
+
if (session.document !== undefined) session.document.write(updated);
|
|
62
|
+
else session.memory = updated;
|
|
63
|
+
|
|
64
|
+
this.notify(this.changedListeners, player, updated);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Runs `callback` when a player's data has finished loading. */
|
|
68
|
+
onLoaded(callback: Listener): void {
|
|
69
|
+
this.loadedListeners.push(callback);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Runs `callback` each time a player's data changes through `update`. */
|
|
73
|
+
onChanged(callback: Listener): void {
|
|
74
|
+
this.changedListeners.push(callback);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private load(player: Player): void {
|
|
78
|
+
if (this.sessions.has(player)) return;
|
|
79
|
+
|
|
80
|
+
collection
|
|
81
|
+
.load(`Player_${player.UserId}`, [player.UserId])
|
|
82
|
+
.then((document) => {
|
|
83
|
+
// The player left while their data was loading.
|
|
84
|
+
if (player.Parent === undefined) {
|
|
85
|
+
document.close();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Fields added to PlayerData since this player last played get their default.
|
|
90
|
+
const data = { ...DEFAULT_PLAYER_DATA, ...document.read() };
|
|
91
|
+
document.write(data);
|
|
92
|
+
|
|
93
|
+
this.sessions.set(player, { document, memory: data });
|
|
94
|
+
this.notify(this.loadedListeners, player, data);
|
|
95
|
+
})
|
|
96
|
+
.catch((reason) => this.loadFailed(player, reason));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private loadFailed(player: Player, reason: unknown): void {
|
|
100
|
+
warn(`[PlayerData] could not load ${player.Name}'s data: ${tostring(reason)}`);
|
|
101
|
+
|
|
102
|
+
if (RunService.IsStudio()) {
|
|
103
|
+
// Studio has no DataStore access until it is enabled and the place is
|
|
104
|
+
// published: keep working with temporary data instead of blocking testing.
|
|
105
|
+
warn("[PlayerData] Studio: using temporary data that will NOT be saved.");
|
|
106
|
+
this.sessions.set(player, { memory: { ...DEFAULT_PLAYER_DATA } });
|
|
107
|
+
this.notify(this.loadedListeners, player, DEFAULT_PLAYER_DATA);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// On a live server, playing without saving would silently lose progress
|
|
112
|
+
// (or worse, overwrite it): better to send the player back and let them retry.
|
|
113
|
+
player.Kick("Your data could not be loaded. Please rejoin.");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private unload(player: Player): void {
|
|
117
|
+
const session = this.sessions.get(player);
|
|
118
|
+
this.sessions.delete(player);
|
|
119
|
+
session?.document?.close().catch((reason) => {
|
|
120
|
+
warn(`[PlayerData] could not save ${player.Name}'s data: ${tostring(reason)}`);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private notify(listeners: Listener[], player: Player, data: Readonly<PlayerData>): void {
|
|
125
|
+
for (const listener of listeners) task.spawn(listener, player, data);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "@rbxts/react";
|
|
2
|
+
import { HomeScreen } from "./screens/HomeScreen";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The root of your interface. Every screen of the game is listed here, and
|
|
6
|
+
* `rowork make:screen` adds the new ones to this list for you.
|
|
7
|
+
*
|
|
8
|
+
* A screen is a component that returns a `screengui`; `<>` ... `</>` groups them
|
|
9
|
+
* without adding anything to the game. The lowercase tags (`screengui`, `frame`,
|
|
10
|
+
* `textbutton`...) are Roblox instances; your own components start with a capital.
|
|
11
|
+
*/
|
|
12
|
+
export function App() {
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<HomeScreen />
|
|
16
|
+
{/* rowork:screens */}
|
|
17
|
+
</>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "@rbxts/react";
|
|
2
|
+
import ReactRoblox from "@rbxts/react-roblox";
|
|
3
|
+
import { CreateReactStory } from "@rbxts/ui-labs";
|
|
4
|
+
import { Button } from "./Button";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A story shows one component on its own, inside Studio, without running the game
|
|
8
|
+
* (open the UI Labs plugin). `controls` become fields you can change live.
|
|
9
|
+
*/
|
|
10
|
+
export = CreateReactStory(
|
|
11
|
+
{ react: React, reactRoblox: ReactRoblox, controls: { text: "Click me" } },
|
|
12
|
+
(props) => <Button text={props.controls.text} />,
|
|
13
|
+
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "@rbxts/react";
|
|
2
|
+
|
|
3
|
+
interface ButtonProps {
|
|
4
|
+
text: string;
|
|
5
|
+
onClick?: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A button. Copy this file to make your own components: one component per file,
|
|
10
|
+
* with a `.story.tsx` next to it to see it in Studio without running the game.
|
|
11
|
+
*/
|
|
12
|
+
export function Button({ text, onClick }: ButtonProps) {
|
|
13
|
+
return (
|
|
14
|
+
<textbutton
|
|
15
|
+
Size={UDim2.fromOffset(200, 50)}
|
|
16
|
+
Text={text}
|
|
17
|
+
TextScaled
|
|
18
|
+
Event={{ Activated: () => onClick?.() }}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Controller, OnStart } from "@flamework/core";
|
|
2
|
+
import React from "@rbxts/react";
|
|
3
|
+
import { createPortal, createRoot } from "@rbxts/react-roblox";
|
|
4
|
+
import { App } from "{{ appImport }}";
|
|
5
|
+
|
|
6
|
+
const Players = game.GetService("Players");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Puts the React interface on the player's screen when the game starts.
|
|
10
|
+
*
|
|
11
|
+
* `App` returns ScreenGuis, which only work inside a player's PlayerGui. React draws into
|
|
12
|
+
* an instance it is given, so a throwaway Folder is the root and `createPortal` sends
|
|
13
|
+
* what `App` draws to the PlayerGui.
|
|
14
|
+
*/
|
|
15
|
+
@Controller()
|
|
16
|
+
export class UiController implements OnStart {
|
|
17
|
+
onStart(): void {
|
|
18
|
+
const playerGui = Players.LocalPlayer.WaitForChild("PlayerGui");
|
|
19
|
+
createRoot(new Instance("Folder")).render(createPortal(<App />, playerGui));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { useState } from "@rbxts/react";
|
|
2
|
+
import { Button } from "../Button";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An example screen: a ScreenGui with one button. `key` is the name it gets in the game (PlayerGui > Home). `useState` keeps a value that redraws
|
|
6
|
+
* the interface when it changes. Make more with `rowork make:screen`, and add elements
|
|
7
|
+
* to any screen with `rowork make:ui <name> --in Home`.
|
|
8
|
+
*/
|
|
9
|
+
export function HomeScreen() {
|
|
10
|
+
const [count, setCount] = useState(0);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<screengui key="Home" ResetOnSpawn={false} ZIndexBehavior={Enum.ZIndexBehavior.Sibling}>
|
|
14
|
+
<frame Size={UDim2.fromScale(1, 1)} BackgroundTransparency={1}>
|
|
15
|
+
<Button text={`Clicked ${count} times`} onClick={() => setCount(count + 1)} />
|
|
16
|
+
{/* rowork:elements */}
|
|
17
|
+
</frame>
|
|
18
|
+
</screengui>
|
|
19
|
+
);
|
|
20
|
+
}
|