You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+47-17Lines changed: 47 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,35 +26,62 @@ The plugin is the source of truth. Menu files stay under `plugins/BlueMenu/menus
26
26
27
27
## How a session works
28
28
29
-
1. A player runs `/bm editor` in game. The plugin opens a session against `wss://menu.blueva.net/ws` and hands the player a link.
30
-
2. Opening the link binds that browser window to the session. Each window carries its own verification id, so a leaked link does not grant access on its own.
31
-
3. If `require-confirmation` is on in `settings.yml`, the plugin waits for `/bm confirm` in game before the session becomes editable.
32
-
4.The editor requests the menu list, loads a menu, and saves changes back through the same socket. With `auto-save` and `auto-reload` enabled, the plugin writes the YAML and reloads the menu immediately.
29
+
1. A player runs `/bm editor` in game. The plugin asks the editor to open a session and hands the player a link.
30
+
2. Opening the link registers that browser window and gives it its own verification id, so a leaked link does not grant access on its own.
31
+
3. If `require-confirmation` is on in `settings.yml`, the plugin waits for `/bm confirm <id>` in game before the session becomes editable.
32
+
4.From then on the browser edits over plain HTTP. Every operation that needs the server is forwarded to the plugin and answered by it.
33
33
34
-
Sessions expire on their own, and the plugin rejects any message whose session is unknown, consumed or unconfirmed.
34
+
Sessions expire on their own, and the editor rejects any request whose session is unknown, consumed or unconfirmed.
35
+
36
+
## How the plugin is reached
37
+
38
+
The plugin is not a client the editor can call directly, so requests travel to it over a broadcast channel and come back over HTTP:
39
+
40
+
- The server registers once and stores its credentials in `webeditor-credentials.yml`.
41
+
- It subscribes to its own private Reverb channel and keeps itself marked as reachable with a heartbeat.
42
+
- A browser request that needs the server publishes an RPC request on that channel and waits; the plugin performs the operation and posts the answer back to `/api/plugin/rpc-response`.
43
+
44
+
That wait happens **inside** the browser's request while the answer arrives on a **different** request, so the web process must serve more than one request at a time. With a single worker the waiting request starves the one that would release it:
`artisan serve` only honours `PHP_CLI_SERVER_WORKERS` together with `--no-reload`.
51
+
52
+
## Demo mode
53
+
54
+
Opening the site without a session shows the editor running on the example menus the plugin ships. Everything renders and every editor works; only saving is unavailable, because there is no server behind it.
35
55
36
56
## Stack
37
57
38
-
- Laravel 13 on PHP 8.3+
58
+
- Laravel 13 on PHP 8.3+, with Laravel Reverb for the channel the plugin listens on
39
59
- React 19 with TypeScript 7, mounted from a Blade shell
60
+
- CodeMirror 6 for the YAML editor, `yaml` for the document model
40
61
- Vite 8 with the Laravel plugin, Tailwind 4 and Bunny Fonts
41
62
- SQLite by default, MySQL in production
42
-
- PHPUnit for tests
63
+
- PHPUnit for the backend, Vitest for the editor
43
64
44
65
## Project Layout
45
66
46
67
```
47
68
app/
48
-
├── Http/Controllers/ HTTP entry points
49
-
├── Models/ Eloquent models
50
-
└── Providers/ service providers
69
+
├── Enums/ domain vocabularies
70
+
├── Events/ broadcast events, including the plugin RPC request
71
+
├── Http/Controllers/Api/ browser endpoints
72
+
├── Http/Controllers/Api/Plugin/ endpoints the plugin calls
├── js/editor/ menu model, yaml codec, validator, materials
78
+
├── js/components/ editor chassis
79
+
├── js/components/visual/ canvas, item editor, form builder, animator
80
+
└── views/ Blade shells that mount React
81
+
routes/web.php browser routes
82
+
routes/plugin.php plugin routes
83
+
routes/channels.php private channel authorisation
84
+
public/editor/items/ item sprites, one folder per Minecraft version
58
85
```
59
86
60
87
## Requirements
@@ -65,6 +92,7 @@ tests/ PHPUnit feature and unit tests
65
92
| Composer | 2+ |
66
93
| Node | 20+ |
67
94
| Database | SQLite for local work, MySQL 8+ in production |
95
+
| Reverb | Started with `php artisan reverb:start`|
68
96
69
97
## Getting Started
70
98
@@ -96,15 +124,17 @@ composer dev
96
124
```bash
97
125
npm run dev # Vite dev server with hot reload
98
126
npm run typecheck # tsc --noEmit
127
+
npm test# Vitest, covering the yaml codec and the editor logic
99
128
npm run build # production assets
100
129
composer test# clears config, then runs PHPUnit
130
+
php artisan reverb:start
101
131
```
102
132
103
133
Run the narrowest test set that covers a change, for example `php artisan test --compact --filter=SomeTest`.
104
134
105
135
## Deployment
106
136
107
-
`.github/workflows/deploy.yml` typechecks, builds and runs the test suite on every push and pull request. On `main` it then pulls, installs production dependencies, rebuilds the assets, migrates and warms the caches on the host.
137
+
`.github/workflows/deploy.yml` typechecks, builds and runs both test suites on every push and pull request. On `main` it then pulls, installs production dependencies, rebuilds the assets, migrates and warms the caches on the host.
0 commit comments