Refactor and rebrand Rojo to Atlas

- Renamed the project from Rojo to Atlas, updating all relevant files, scripts, and documentation to reflect the new branding.
- Bumped version to 7.7.0-rc.2 and updated protocol version from 5 to 6.
- Modified installation scripts and CI workflows to use the new binary name and paths.
- Adjusted plugin settings and internal identifiers to prevent conflicts with the original Rojo.
- Enhanced session management and API response handling to support the new server fork identifier.
- Updated project templates and README files to guide users on using Atlas.
This commit is contained in:
Joe 2026-02-07 13:21:52 -06:00
parent 0e263789b0
commit 50b9e18514
54 changed files with 496 additions and 218 deletions

View file

@ -5,7 +5,7 @@ Run the complete CI pipeline: auto-fix all formatting, run all linters, build ev
## Instructions ## Instructions
- If the user's message contains **"rbx-dom"**, run **both** the Rojo and rbx-dom sections below. - If the user's message contains **"rbx-dom"**, run **both** the Rojo and rbx-dom sections below.
- Otherwise, **skip the entire rbx-dom section** (steps 8–13) to save time. - Otherwise, **skip the entire rbx-dom section** (steps 9–14) to save time.
Execute ALL applicable steps in order. Fix issues automatically where possible. Execute ALL applicable steps in order. Fix issues automatically where possible.
@ -23,7 +23,14 @@ stylua plugin/src
cargo fmt cargo fmt
``` ```
### 3. Lua Static Analysis (Selene) - MUST PASS WITH ZERO ISSUES ### 3. Auto-fix TypeScript Formatting (Prettier) for vscode-rojo
```powershell
cd vscode-rojo
npx prettier --write "src/**/*.ts"
cd ..
```
### 4. Lua Static Analysis (Selene) - MUST PASS WITH ZERO ISSUES
```powershell ```powershell
selene plugin/src selene plugin/src
``` ```
@ -38,7 +45,7 @@ If Selene reports ANY errors or warnings:
3. Re-run Selene after fixes to confirm exit code 0 3. Re-run Selene after fixes to confirm exit code 0
4. Only proceed once Selene shows: `Results: 0 errors, 0 warnings, 0 parse errors` 4. Only proceed once Selene shows: `Results: 0 errors, 0 warnings, 0 parse errors`
### 4. Rust Linting (Clippy) - Auto-fix where possible ### 5. Rust Linting (Clippy) - Auto-fix where possible
```powershell ```powershell
cargo clippy --fix --allow-dirty --allow-staged cargo clippy --fix --allow-dirty --allow-staged
``` ```
@ -48,24 +55,23 @@ cargo clippy --all-targets --all-features
``` ```
If there are remaining warnings/errors, fix them before proceeding. If there are remaining warnings/errors, fix them before proceeding.
### 5. Build Everything ### 6. Build Everything
```powershell ```powershell
cargo build --locked --all-targets --all-features cargo build --locked --all-targets --all-features
``` ```
### 6. Run ALL Rust Tests ### 7. Run ALL Rust Tests
```powershell ```powershell
cargo test --locked --all-targets --all-features cargo test --locked --all-targets --all-features
``` ```
### 7. Run Roblox Plugin Tests ### 8. Run Roblox Plugin Tests
On Windows:
**Do NOT use the scripts (`unit-test-plugin.ps1` / `unit-test-plugin.sh`).** They reference a system-installed binary which may not exist. Always use the freshly built binary from step 6.
```powershell ```powershell
.\scripts\unit-test-plugin.ps1 .\target\debug\atlas.exe build plugin/test-place.project.json -o TestPlace.rbxl
``` run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl
Otherwise:
```bash
bash scripts/unit-test-plugin.sh
``` ```
--- ---
@ -74,30 +80,30 @@ bash scripts/unit-test-plugin.sh
All rbx-dom steps run inside the `rbx-dom/` directory. All rbx-dom steps run inside the `rbx-dom/` directory.
### 8. Auto-fix Lua Formatting (Stylua) for rbx_dom_lua ### 9. Auto-fix Lua Formatting (Stylua) for rbx_dom_lua
```powershell ```powershell
cd rbx-dom cd rbx-dom
stylua rbx_dom_lua/src stylua rbx_dom_lua/src
cd .. cd ..
``` ```
### 9. Auto-fix Rust Formatting ### 10. Auto-fix Rust Formatting
```powershell ```powershell
cd rbx-dom cd rbx-dom
cargo fmt cargo fmt
cd .. cd ..
``` ```
### 10. Lua Static Analysis (Selene) for rbx_dom_lua - MUST PASS WITH ZERO ISSUES ### 11. Lua Static Analysis (Selene) for rbx_dom_lua - MUST PASS WITH ZERO ISSUES
```powershell ```powershell
cd rbx-dom cd rbx-dom
selene rbx_dom_lua/src selene rbx_dom_lua/src
cd .. cd ..
``` ```
Same rules as step 3: exit code 0 required, fix all errors and warnings before proceeding. Same rules as step 4: exit code 0 required, fix all errors and warnings before proceeding.
### 11. Rust Linting (Clippy) - Auto-fix where possible ### 12. Rust Linting (Clippy) - Auto-fix where possible
```powershell ```powershell
cd rbx-dom cd rbx-dom
cargo clippy --fix --allow-dirty --allow-staged cargo clippy --fix --allow-dirty --allow-staged
@ -110,7 +116,7 @@ cd ..
``` ```
If there are remaining warnings/errors, fix them before proceeding. If there are remaining warnings/errors, fix them before proceeding.
### 12. Build rbx-dom ### 13. Build rbx-dom
```powershell ```powershell
cd rbx-dom cd rbx-dom
cargo build --verbose cargo build --verbose
@ -118,7 +124,7 @@ cargo build --all-features --verbose
cd .. cd ..
``` ```
### 13. Run ALL rbx-dom Rust Tests ### 14. Run ALL rbx-dom Rust Tests
```powershell ```powershell
cd rbx-dom cd rbx-dom
cargo test --verbose cargo test --verbose
@ -140,6 +146,7 @@ After ALL steps complete, provide a summary:
Formatting: Formatting:
- Stylua: [fixed X files / no changes needed] - Stylua: [fixed X files / no changes needed]
- Rustfmt: [fixed X files / no changes needed] - Rustfmt: [fixed X files / no changes needed]
- Prettier (vscode-rojo): [fixed X files / no changes needed]
Linting: Linting:
- Selene: PASS (0 errors, 0 warnings) / FAIL (X errors, Y warnings) - Selene: PASS (0 errors, 0 warnings) / FAIL (X errors, Y warnings)

View file

@ -0,0 +1,206 @@
---
name: Atlas Fork Isolation
overview: Change default port, add a server fork identifier, rename settings prefix, rename plugin rbxm, rename binary to atlas, update VS Code extension binary references, and rename internal Studio markers so Atlas and stock Rojo can coexist without conflicts.
todos:
- id: port
content: Change default port from 34872 to 34873 in serve.rs and Config.lua
status: completed
- id: version
content: Bump version in Cargo.toml and plugin/Version.txt
status: completed
- id: protocol
content: Bump protocol version 5->6 in interface.rs and Config.lua
status: completed
- id: fork-id
content: Add serverFork field to ServerInfoResponse, populate with 'atlas', validate in plugin ApiContext.lua and Types.lua
status: completed
- id: settings
content: Change settings prefix from Rojo_ to Atlas_ in Settings.lua
status: completed
- id: session-markers
content: Rename __Rojo_SessionLock and __Rojo_ConnectionUrl to __Atlas_ in App/init.lua
status: completed
- id: widget-ids
content: Rename Rojo_ prefixed widget IDs to Atlas_ in Confirming.lua and Connected.lua
status: completed
- id: rbxm-managed
content: Rename RojoManagedPlugin.rbxm to AtlasManagedPlugin.rbxm in plugin.rs
status: completed
- id: rbxm-build
content: Rename Rojo.rbxm to Atlas.rbxm in build scripts, install scripts, and release workflow
status: completed
- id: binary-rename
content: "Rename binary: Cargo.toml name rojo->atlas, CARGO_BIN_EXE in tests, clap name, release workflow BIN, install script binary refs"
status: completed
- id: vscode-binary-refs
content: "Change all rojo binary invocations to atlas in vscode-rojo: getRojoInstall, installPlugin, serveProject, buildProject, createProjectFile, openMenu"
status: completed
- id: bugfix-waypoint
content: "Fix broken undo detection: App/init.lua checks '^Rojo: Patch' but ServeSession already records as 'Atlas: Patch'"
status: completed
- id: templates
content: Update project template READMEs and init.rs CLI output to say atlas instead of rojo
status: completed
isProject: false
---
# Atlas Fork Isolation from Stock Rojo
## 1. Default Port: 34872 -> 34873
**Server:**
- `[src/cli/serve.rs](src/cli/serve.rs)` line 15: `DEFAULT_PORT: u16 = 34872` -> `34873`
- Same file line 28-29: update help text from `34872` to `34873`
**Plugin:**
- `[plugin/src/Config.lua](plugin/src/Config.lua)` line 32: `defaultPort = "34872"` -> `"34873"`
## 2. Version Bump + Unique Server Fork Identifier
**Version bump** (both must match per `build.rs` assertion):
- `[Cargo.toml](Cargo.toml)` line 3: bump `version` (e.g. `"7.7.0-rc.1"` -> `"7.7.0-rc.2"` or whatever the next version should be)
- `[plugin/Version.txt](plugin/Version.txt)`: match the same value
**Protocol version bump:**
- `[src/web/interface.rs](src/web/interface.rs)` line 28: `PROTOCOL_VERSION: u64 = 5` -> `6`
- `[plugin/src/Config.lua](plugin/src/Config.lua)` line 30: `protocolVersion = 5` -> `6`
**Add `serverFork` field to `ServerInfoResponse**` so the plugin can reject non-Atlas servers even if protocol versions coincidentally match in the future:
- `[src/web/interface.rs](src/web/interface.rs)`: add `pub server_fork: String` to `ServerInfoResponse` (serializes as `"serverFork"`)
- `[src/web/api.rs](src/web/api.rs)` ~line 272: include `server_fork: "atlas".to_owned()` when constructing the response
- `[plugin/src/Types.lua](plugin/src/Types.lua)` ~line 38: add `serverFork = t.string` to `ApiInfoResponse`
- `[plugin/src/ApiContext.lua](plugin/src/ApiContext.lua)` ~line 27: add a `rejectWrongFork` check that validates `infoResponseBody.serverFork == "atlas"`, rejecting with a clear message if it's a stock Rojo server
## 3. Plugin Settings Prefix: `Rojo_` -> `Atlas_`
- `[plugin/src/Settings.lua](plugin/src/Settings.lua)`: change `"Rojo_"` to `"Atlas_"` on lines 41, 45, 70 (3 occurrences, all share the same pattern)
## 4. Session Lock + Connection Attribute Naming
These are stored on real instances in Studio and would conflict if both plugins are loaded:
- `[plugin/src/App/init.lua](plugin/src/App/init.lua)`: rename `"__Rojo_SessionLock"` -> `"__Atlas_SessionLock"` (lines 321, 348, 351, 365)
- Same file: rename `"__Rojo_ConnectionUrl"` -> `"__Atlas_ConnectionUrl"` (lines 534, 547, 557, 561)
## 5. Ephemeral Widget IDs: `Rojo_` -> `Atlas_`
These are `CreateDockWidgetPluginGui` IDs that persist across sessions and would clash:
- `[plugin/src/App/StatusPages/Confirming.lua](plugin/src/App/StatusPages/Confirming.lua)`: 4 IDs (`Rojo_ConfirmingStringDiff`, `Rojo_ConfirmingTableDiff`, `Rojo_AcceptConfirm`, `Rojo_DiffSync`)
- `[plugin/src/App/StatusPages/Connected.lua](plugin/src/App/StatusPages/Connected.lua)`: 3 IDs (`Rojo_ChangesViewer`, `Rojo_ConnectedStringDiff`, `Rojo_ConnectedTableDiff`)
## 6. Plugin RBXM Naming: `Rojo.rbxm` -> `Atlas.rbxm`
`**rojo plugin install` command:**
- `[src/cli/plugin.rs](src/cli/plugin.rs)` line 13: `PLUGIN_FILE_NAME = "RojoManagedPlugin.rbxm"` -> `"AtlasManagedPlugin.rbxm"`
**Build scripts:**
- `[scripts/watch-build-plugin.sh](scripts/watch-build-plugin.sh)`: `Rojo.rbxm` -> `Atlas.rbxm`, `rojo build` -> `atlas build`
- `[scripts/watch-build-plugin.ps1](scripts/watch-build-plugin.ps1)`: same
- `[scripts/unit-test-plugin.sh](scripts/unit-test-plugin.sh)`: `rojo build` -> `atlas build`
- `[scripts/unit-test-plugin.ps1](scripts/unit-test-plugin.ps1)`: `rojo build` -> `atlas build`
- `[install.sh](install.sh)`: `Rojo.rbxm` -> `Atlas.rbxm`, `./target/$MODE/rojo` -> `./target/$MODE/atlas`, `pkill -f rojo` -> `pkill -f atlas`
- `[install.ps1](install.ps1)`: `Rojo.rbxm` -> `Atlas.rbxm`, `rojo.exe` -> `atlas.exe`, `rojo.pdb` -> `atlas.pdb`, `C:\Program Files\Rojo` -> `C:\Program Files\Atlas`, `Stop-Process -Name "rojo"` -> `Stop-Process -Name "atlas"`
**GitHub Actions:**
- `[.github/workflows/release.yml](.github/workflows/release.yml)`:
- Line 34: `rojo build` -> `atlas build` (but this uses rokit's stock rojo -- see note below)
- Line 88: `BIN: rojo` -> `BIN: atlas`
- Lines 34, 40, 45, 46: `Rojo.rbxm` -> `Atlas.rbxm`
**Note on CI plugin build:** Release workflow line 34 uses rokit-installed `rojo` to build the plugin rbxm artifact. After binary rename, the locally compiled binary is `atlas`, but rokit installs stock `rojo`. Two options:
- Option A: Change CI to compile atlas first, then use `atlas build` for the plugin (requires reordering jobs or combining them)
- Option B: Keep using rokit's stock `rojo build` for the plugin artifact (the `build` command is format-compatible)
- **Recommend Option A** for correctness -- the build-plugin step should use the atlas binary from the build step.
## 7. Binary Rename: `rojo` -> `atlas`
**Cargo.toml:**
- `[Cargo.toml](Cargo.toml)` line 2: `name = "rojo"` -> `name = "atlas"` (changes binary output from `rojo`/`rojo.exe` to `atlas`/`atlas.exe`)
- `[lib] name = "librojo"` stays unchanged (line 41) -- this keeps all `use librojo::` imports working without cascading changes to ~20 test/bench files
**CLI display name:**
- `[src/cli/mod.rs](src/cli/mod.rs)` line 36: `#[clap(name = "Rojo"...)]` -> `#[clap(name = "Atlas"...)]`
**Test binary path resolution:**
- `[tests/rojo_test/io_util.rs](tests/rojo_test/io_util.rs)` line 10: `env!("CARGO_BIN_EXE_rojo")` -> `env!("CARGO_BIN_EXE_atlas")` (Cargo auto-generates this env var from the binary name)
## 8. VS Code Extension: Binary Invocations `rojo` -> `atlas`
The extension package is already rebranded (`vscode-atlas`, commands `vscode-atlas.*`, config `atlas.*`). But source files still invoke the `rojo` binary:
- `[vscode-rojo/src/getRojoInstall.ts](vscode-rojo/src/getRojoInstall.ts)`:
- Line 46: `which("rojo")` -> `which("atlas")`
- Line 56: `exec("rojo --version", ...)` -> `exec("atlas --version", ...)`
- `[vscode-rojo/src/installPlugin.ts](vscode-rojo/src/installPlugin.ts)`:
- Line 13: `exec("rojo plugin install", ...)` -> `exec("atlas plugin install", ...)`
- `[vscode-rojo/src/serveProject.ts](vscode-rojo/src/serveProject.ts)`:
- Line 30: `terminal.sendText('rojo serve ...')` -> `terminal.sendText('atlas serve ...')`
- `[vscode-rojo/src/buildProject.ts](vscode-rojo/src/buildProject.ts)`:
- Line 24: `exec('rojo build ...')` -> `exec('atlas build ...')`
- `[vscode-rojo/src/createProjectFile.ts](vscode-rojo/src/createProjectFile.ts)`:
- Line 8: `exec("rojo init", ...)` -> `exec("atlas init", ...)`
- `[vscode-rojo/src/commands/openMenu.ts](vscode-rojo/src/commands/openMenu.ts)`:
- Line 164: `which("rojo")` -> `which("atlas")`
- Line 571: `terminal.sendText('rojo studio ...')` -> `terminal.sendText('atlas studio ...')`
- Line 602: `terminal.sendText('rojo syncback ...')` -> `terminal.sendText('atlas syncback ...')`
**Persisted state key:**
- `[vscode-rojo/src/serveProject.ts](vscode-rojo/src/serveProject.ts)` line 16 and `[vscode-rojo/src/commands/serveRecent.ts](vscode-rojo/src/commands/serveRecent.ts)` line 10: `"rojoLastPath"` -> `"atlasLastPath"`
**Aftman install references** (in `installRojo.ts` lines 183, 201, 210): These reference `rojo-rbx/rojo` for auto-installing. Left as-is for now since our fork may not be published to aftman yet. Will need updating when distribution is set up.
## 9. Bugfix: Undo Waypoint Detection
`ServeSession.lua:529` already records as `"Atlas: Patch ..."` but `App/init.lua:66` still checks for `"^Rojo: Patch"`. This means undo detection is currently broken.
- `[plugin/src/App/init.lua](plugin/src/App/init.lua)` line 66: `"^Rojo: Patch"` -> `"^Atlas: Patch"`
## 10. Project Templates and CLI Output: `rojo` -> `atlas`
**Template READMEs:**
- `[assets/project-templates/place/README.md](assets/project-templates/place/README.md)`: `Generated by [Rojo](...)` -> `Generated by [Atlas](...)`, `rojo serve` -> `atlas serve`, `rojo syncback` -> `atlas syncback`
- `[assets/project-templates/model/README.md](assets/project-templates/model/README.md)`: same pattern, `rojo build` -> `atlas build`
- `[assets/project-templates/plugin/README.md](assets/project-templates/plugin/README.md)`: same pattern, `rojo build` -> `atlas build`
**CLI print:**
- `[src/cli/init.rs](src/cli/init.rs)` line 206: `"Run 'rojo syncback' to sync your place."` -> `"Run 'atlas syncback' to sync your place."`
---
## What We Are NOT Changing (and why)
| Item | Reason |
| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `plugin.project.json` name `"Rojo"` | Would require updating `FindFirstAncestor("Rojo")` in 50+ Lua files; each plugin loads its own tree, no cross-plugin conflict |
| `[lib] name = "librojo"` | Keeps all `use librojo::` imports working in ~20 test/bench files |
| `/api/rojo` endpoint path | Internal protocol between our server and our plugin; not user-facing |
| `handle_api_rojo` / `get_api_rojo` method names | Internal Rust/test method names; cosmetic |
| `Rojo_Id`, `Rojo_Target_`, `Rojo_Ref_` attribute names | Data format embedded in existing Roblox files; changing breaks backward compatibility |
| `ROJO_DEV_BUILD` instance name | Internal dev flag within plugin tree; no cross-plugin conflict |
| `ROJO_SYNCBACK_DEBUG` env var | Internal debug var; cosmetic |
| `rojo-test/` directory, `mod rojo_test`, `rojo-insta-ext` crate | Internal test infrastructure; not derived from package name, still works |
| `rokit.toml` `rojo = "rojo-rbx/rojo@7.5.1"` | Dev tool dependency for stock rojo; doesn't affect our binary |
| `build/windows/rojo-manifest.rc` and `rojo.manifest` | Windows manifest files; paths are hardcoded in build.rs, not derived from package name |
| `RojoTree`, `RojoRef`, etc. type names | Internal Rust types; cosmetic |
| Comments, doc strings, error messages (~150 occurrences) | Cosmetic only; no functional conflict |
| `plugin/Packages/` vendored dependencies | Third-party code; must not touch |
| `vscode-rojo/src/installRojo.ts` aftman refs | Distribution not set up yet; update later |

View file

@ -25,25 +25,26 @@ jobs:
with: with:
submodules: true submodules: true
- name: Setup Rokit - name: Install Rust
uses: CompeyDev/setup-rokit@v0.1.2 uses: dtolnay/rust-toolchain@stable
with:
version: 'v1.1.0' - name: Build Atlas
run: cargo build --release --locked
- name: Build Plugin - name: Build Plugin
run: rojo build plugin.project.json --output Rojo.rbxm run: ./target/release/atlas build plugin.project.json --output Atlas.rbxm
- name: Upload Plugin to Release - name: Upload Plugin to Release
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
gh release upload ${{ github.ref_name }} Rojo.rbxm gh release upload ${{ github.ref_name }} Atlas.rbxm
- name: Upload Plugin to Artifacts - name: Upload Plugin to Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: Rojo.rbxm name: Atlas.rbxm
path: Rojo.rbxm path: Atlas.rbxm
build: build:
needs: ["create-release"] needs: ["create-release"]
@ -85,7 +86,7 @@ jobs:
name: Build (${{ matrix.target }}) name: Build (${{ matrix.target }})
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
BIN: rojo BIN: atlas
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:

134
Cargo.lock generated
View file

@ -170,6 +170,73 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "atlas"
version = "7.7.0-rc.2"
dependencies = [
"anyhow",
"backtrace",
"bincode",
"blake3",
"bytes",
"clap 4.5.57",
"criterion",
"crossbeam-channel",
"csv",
"data-encoding",
"embed-resource",
"env_logger 0.11.8",
"float-cmp",
"fs-err",
"futures",
"globset",
"http-body-util",
"humantime",
"hyper",
"hyper-tungstenite",
"hyper-util",
"indexmap",
"insta",
"jod-thread",
"json5",
"log",
"maplit",
"memofs",
"num_cpus",
"opener",
"paste",
"pretty_assertions",
"profiling",
"rayon",
"rbx_binary",
"rbx_cookie",
"rbx_dom_weak",
"rbx_reflection",
"rbx_reflection_database",
"rbx_xml",
"regex",
"reqwest",
"ritz",
"rmp-serde",
"roblox_install",
"rojo-insta-ext",
"semver 1.0.27",
"serde",
"serde_bytes",
"serde_json",
"serde_yaml",
"strum",
"tempfile",
"termcolor",
"thiserror 2.0.18",
"tokio",
"toml",
"uuid",
"walkdir",
"winreg 0.55.0",
"yaml-rust2",
]
[[package]] [[package]]
name = "atomic-waker" name = "atomic-waker"
version = "1.1.2" version = "1.1.2"
@ -2566,73 +2633,6 @@ dependencies = [
"winreg 0.6.2", "winreg 0.6.2",
] ]
[[package]]
name = "rojo"
version = "7.7.0-rc.1"
dependencies = [
"anyhow",
"backtrace",
"bincode",
"blake3",
"bytes",
"clap 4.5.57",
"criterion",
"crossbeam-channel",
"csv",
"data-encoding",
"embed-resource",
"env_logger 0.11.8",
"float-cmp",
"fs-err",
"futures",
"globset",
"http-body-util",
"humantime",
"hyper",
"hyper-tungstenite",
"hyper-util",
"indexmap",
"insta",
"jod-thread",
"json5",
"log",
"maplit",
"memofs",
"num_cpus",
"opener",
"paste",
"pretty_assertions",
"profiling",
"rayon",
"rbx_binary",
"rbx_cookie",
"rbx_dom_weak",
"rbx_reflection",
"rbx_reflection_database",
"rbx_xml",
"regex",
"reqwest",
"ritz",
"rmp-serde",
"roblox_install",
"rojo-insta-ext",
"semver 1.0.27",
"serde",
"serde_bytes",
"serde_json",
"serde_yaml",
"strum",
"tempfile",
"termcolor",
"thiserror 2.0.18",
"tokio",
"toml",
"uuid",
"walkdir",
"winreg 0.55.0",
"yaml-rust2",
]
[[package]] [[package]]
name = "rojo-insta-ext" name = "rojo-insta-ext"
version = "0.1.0" version = "0.1.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rojo" name = "atlas"
version = "7.7.0-rc.1" version = "7.7.0-rc.2"
rust-version = "1.88" rust-version = "1.88"
authors = [ authors = [
"Lucien Greathouse <me@lpghatguy.com>", "Lucien Greathouse <me@lpghatguy.com>",

View file

@ -1,11 +1,11 @@
# {project_name} # {project_name}
Generated by [Rojo](https://github.com/rojo-rbx/rojo) {rojo_version}. Generated by [Atlas](https://github.com/UserGeneratedLLC/rojo) {rojo_version}.
## Getting Started ## Getting Started
To build this library, use: To build this library, use:
```bash ```bash
rojo build -o "{project_name}.rbxmx" atlas build -o "{project_name}.rbxmx"
``` ```
For more help, check out [the Rojo documentation](https://rojo.space/docs). For more help, check out [the Rojo documentation](https://rojo.space/docs).

View file

@ -5,6 +5,6 @@ Generated by [Atlas](https://github.com/UserGeneratedLLC/rojo).
## Commands ## Commands
```bash ```bash
rojo serve atlas serve
rojo syncback atlas syncback
``` ```

View file

@ -1,17 +1,17 @@
# {project_name} # {project_name}
Generated by [Rojo](https://github.com/rojo-rbx/rojo) {rojo_version}. Generated by [Atlas](https://github.com/UserGeneratedLLC/rojo) {rojo_version}.
## Getting Started ## Getting Started
To build this plugin to your local plugins folder, use: To build this plugin to your local plugins folder, use:
```bash ```bash
rojo build -p "{project_name}.rbxm" atlas build -p "{project_name}.rbxm"
``` ```
You can include the `watch` flag to re-build it on save: You can include the `watch` flag to re-build it on save:
```bash ```bash
rojo build -p "{project_name}.rbxm" --watch atlas build -p "{project_name}.rbxm" --watch
``` ```
For more help, check out [the Rojo documentation](https://rojo.space/docs). For more help, check out [the Rojo documentation](https://rojo.space/docs).

View file

@ -2,7 +2,7 @@
param([string]$Mode = "release") param([string]$Mode = "release")
$InstallDir = "C:\Program Files\Rojo" $InstallDir = "C:\Program Files\Atlas"
Set-Location $PSScriptRoot Set-Location $PSScriptRoot
if ($Mode -eq "release") { if ($Mode -eq "release") {
@ -10,14 +10,14 @@ if ($Mode -eq "release") {
} else { } else {
cargo build "--$Mode" cargo build "--$Mode"
} }
$Rojo = ".\target\$Mode\rojo.exe" $Atlas = ".\target\$Mode\atlas.exe"
& "$Rojo" build plugin.project.json --plugin Rojo.rbxm & "$Atlas" build plugin.project.json --plugin Atlas.rbxm
if ($LASTEXITCODE -ne 0) { throw "Plugin build failed" } if ($LASTEXITCODE -ne 0) { throw "Plugin build failed" }
gsudo Stop-Process -Name "rojo" -Force -ErrorAction SilentlyContinue gsudo Stop-Process -Name "atlas" -Force -ErrorAction SilentlyContinue
gsudo New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null gsudo New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
gsudo Copy-Item "$Rojo" "$InstallDir\" gsudo Copy-Item "$Atlas" "$InstallDir\"
gsudo Copy-Item ".\target\$Mode\rojo.pdb" "$InstallDir\" gsudo Copy-Item ".\target\$Mode\atlas.pdb" "$InstallDir\"
$MachinePath = [Environment]::GetEnvironmentVariable("Path", "Machine") $MachinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($MachinePath -notlike "*$InstallDir*") { if ($MachinePath -notlike "*$InstallDir*") {

View file

@ -6,7 +6,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
cargo build "--$MODE" cargo build "--$MODE"
ROJO="./target/$MODE/rojo" ATLAS="./target/$MODE/atlas"
"$ROJO" build plugin.project.json --plugin Rojo.rbxm "$ATLAS" build plugin.project.json --plugin Atlas.rbxm
pkill -f rojo || true pkill -f atlas || true
sudo cp "$ROJO" /usr/local/bin/ sudo cp "$ATLAS" /usr/local/bin/

View file

@ -1 +1 @@
7.7.0-rc.1 7.7.0-rc.2

View file

@ -27,11 +27,10 @@ end
local function rejectWrongProtocolVersion(infoResponseBody) local function rejectWrongProtocolVersion(infoResponseBody)
if infoResponseBody.protocolVersion ~= Config.protocolVersion then if infoResponseBody.protocolVersion ~= Config.protocolVersion then
local message = ( local message = (
"Found a Rojo dev server, but it's using a different protocol version, and is incompatible." "Found a server, but it's using a different protocol version, and is incompatible."
.. "\nMake sure you have matching versions of both the Rojo plugin and server!" .. "\nMake sure you have matching versions of both the Atlas plugin and server!"
.. "\n\nYour client is version %s, with protocol version %s. It expects server version %s." .. "\n\nYour client is version %s, with protocol version %s. It expects server version %s."
.. "\nYour server is version %s, with protocol version %s." .. "\nYour server is version %s, with protocol version %s."
.. "\n\nGo to https://github.com/rojo-rbx/rojo for more details."
):format( ):format(
Version.display(Config.version), Version.display(Config.version),
Config.protocolVersion, Config.protocolVersion,
@ -46,6 +45,20 @@ local function rejectWrongProtocolVersion(infoResponseBody)
return Promise.resolve(infoResponseBody) return Promise.resolve(infoResponseBody)
end end
local function rejectWrongFork(infoResponseBody)
if infoResponseBody.serverFork ~= "atlas" then
local message = (
"Found a Rojo server, but this plugin requires an Atlas server."
.. "\nThe stock Rojo server is not compatible with the Atlas plugin."
.. "\nMake sure you are running 'atlas serve' instead of 'rojo serve'."
)
return Promise.reject(message)
end
return Promise.resolve(infoResponseBody)
end
local function rejectWrongPlaceId(infoResponseBody) local function rejectWrongPlaceId(infoResponseBody)
if infoResponseBody.expectedPlaceIds ~= nil then if infoResponseBody.expectedPlaceIds ~= nil then
local foundId = table.find(infoResponseBody.expectedPlaceIds, game.PlaceId) local foundId = table.find(infoResponseBody.expectedPlaceIds, game.PlaceId)
@ -147,6 +160,7 @@ function ApiContext:connect()
:andThen(rejectFailedRequests) :andThen(rejectFailedRequests)
:andThen(Http.Response.msgpack) :andThen(Http.Response.msgpack)
:andThen(rejectWrongProtocolVersion) :andThen(rejectWrongProtocolVersion)
:andThen(rejectWrongFork)
:andThen(function(body) :andThen(function(body)
assert(validateApiInfo(body)) assert(validateApiInfo(body))

View file

@ -81,9 +81,49 @@ function SelectionOption:render()
local buttonWidth = if props.text == "Studio" then 44 else 36 local buttonWidth = if props.text == "Studio" then 44 else 36
-- Transparency logic with hover effect -- Transparency logic with hover effect
-- Combines real hover state with subtree highlight binding so the matching
-- button on child nodes looks hovered when a parent's button is hovered.
local bgTransparency, txtTransparency local bgTransparency, txtTransparency
local subtreeBinding = props.subtreeHighlightBinding
local ancestorIds = props.ancestorIds
if subtreeBinding and ancestorIds then
local optionType = props.optionType
local joined = Roact.joinBindings({
transparency = props.transparency,
highlight = subtreeBinding,
})
bgTransparency = joined:map(function(values)
local t = values.transparency
local info = values.highlight
local subtreeHov = info ~= nil and ancestorIds[info.nodeId] == true and info.optionType == optionType
local hov = isHovered or subtreeHov
if isParentOnly then
return if hov then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
elseif isSelected then
return if hov then 0 + (1 * t) else 0.1 + (0.9 * t)
else
return if hov then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
end
end)
txtTransparency = joined:map(function(values)
local t = values.transparency
local info = values.highlight
local subtreeHov = info ~= nil and ancestorIds[info.nodeId] == true and info.optionType == optionType
local hov = isHovered or subtreeHov
if isParentOnly then
return if hov then 0 + t else 0.3 + (0.7 * t)
else
return t
end
end)
else
-- Fallback: no subtree highlight available
if isParentOnly then if isParentOnly then
-- Parent-only: partially transparent, less so when hovering the button
bgTransparency = props.transparency:map(function(t) bgTransparency = props.transparency:map(function(t)
return if isHovered then 0.2 + (0.8 * t) else 0.5 + (0.5 * t) return if isHovered then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
end) end)
@ -91,7 +131,6 @@ function SelectionOption:render()
return if isHovered then 0 + t else 0.3 + (0.7 * t) return if isHovered then 0 + t else 0.3 + (0.7 * t)
end) end)
else else
-- Normal buttons: show hover effect by reducing transparency
bgTransparency = props.transparency:map(function(t) bgTransparency = props.transparency:map(function(t)
if isSelected then if isSelected then
return if isHovered then 0 + (1 * t) else 0.1 + (0.9 * t) return if isHovered then 0 + (1 * t) else 0.1 + (0.9 * t)
@ -101,6 +140,7 @@ function SelectionOption:render()
end) end)
txtTransparency = props.transparency txtTransparency = props.transparency
end end
end
return e("TextButton", { return e("TextButton", {
Size = UDim2.new(0, buttonWidth, 0, 18), Size = UDim2.new(0, buttonWidth, 0, 18),
@ -118,7 +158,7 @@ function SelectionOption:render()
self:setState({ isHovered = true }) self:setState({ isHovered = true })
-- Trigger subtree highlight when this button would apply to children -- Trigger subtree highlight when this button would apply to children
if (isParentOnly or (isSelected and hasChildren)) and props.onSubtreeHoverStart then if (isParentOnly or (isSelected and hasChildren)) and props.onSubtreeHoverStart then
props.onSubtreeHoverStart() props.onSubtreeHoverStart(props.optionType)
end end
end, end,
[Roact.Event.MouseLeave] = function() [Roact.Event.MouseLeave] = function()
@ -180,6 +220,8 @@ local function SelectionRadio(props)
layoutOrder = 1, layoutOrder = 1,
hasChildren = hasChildren, hasChildren = hasChildren,
isParentOnly = isParentOnly, isParentOnly = isParentOnly,
subtreeHighlightBinding = props.subtreeHighlightBinding,
ancestorIds = props.ancestorIds,
onSubtreeHoverStart = props.onSubtreeHoverStart, onSubtreeHoverStart = props.onSubtreeHoverStart,
onSubtreeHoverEnd = props.onSubtreeHoverEnd, onSubtreeHoverEnd = props.onSubtreeHoverEnd,
onClick = function() onClick = function()
@ -201,6 +243,8 @@ local function SelectionRadio(props)
layoutOrder = 2, layoutOrder = 2,
hasChildren = hasChildren, hasChildren = hasChildren,
isParentOnly = isParentOnly, isParentOnly = isParentOnly,
subtreeHighlightBinding = props.subtreeHighlightBinding,
ancestorIds = props.ancestorIds,
onSubtreeHoverStart = props.onSubtreeHoverStart, onSubtreeHoverStart = props.onSubtreeHoverStart,
onSubtreeHoverEnd = props.onSubtreeHoverEnd, onSubtreeHoverEnd = props.onSubtreeHoverEnd,
onClick = function() onClick = function()
@ -222,6 +266,8 @@ local function SelectionRadio(props)
layoutOrder = 3, layoutOrder = 3,
hasChildren = hasChildren, hasChildren = hasChildren,
isParentOnly = isParentOnly, isParentOnly = isParentOnly,
subtreeHighlightBinding = props.subtreeHighlightBinding,
ancestorIds = props.ancestorIds,
onSubtreeHoverStart = props.onSubtreeHoverStart, onSubtreeHoverStart = props.onSubtreeHoverStart,
onSubtreeHoverEnd = props.onSubtreeHoverEnd, onSubtreeHoverEnd = props.onSubtreeHoverEnd,
onClick = function() onClick = function()
@ -337,17 +383,6 @@ function DomLabel:render()
local props = self.props local props = self.props
local depth = props.depth or 1 local depth = props.depth or 1
-- Derive subtree highlight state from binding (no re-renders needed)
local ancestorIds = props.ancestorIds
local isSubtreeHighlighted = if props.subtreeHighlightNodeId
then props.subtreeHighlightNodeId:map(function(highlightId)
if highlightId == nil then
return false
end
return ancestorIds[highlightId] == true
end)
else nil
return Theme.with(function(theme) return Theme.with(function(theme)
local color = if props.isWarning local color = if props.isWarning
then theme.Diff.Warning then theme.Diff.Warning
@ -544,17 +579,6 @@ function DomLabel:render()
}) })
else nil, else nil,
}), }),
SubtreeHighlight = if isSubtreeHighlighted
then e("Frame", {
Size = UDim2.fromScale(1, 1),
BackgroundColor3 = theme.Diff.SubtreeHighlight,
BackgroundTransparency = isSubtreeHighlighted:map(function(highlighted)
return if highlighted then 0.92 else 1
end),
BorderSizePixel = 0,
ZIndex = 0,
})
else nil,
SelectionRadio = e(SelectionRadio, { SelectionRadio = e(SelectionRadio, {
-- Visible for nodes with patchType, or for parent-only nodes on hover -- Visible for nodes with patchType, or for parent-only nodes on hover
visible = (props.patchType ~= nil and props.onSelectionChange ~= nil) visible = (props.patchType ~= nil and props.onSelectionChange ~= nil)
@ -572,9 +596,12 @@ function DomLabel:render()
isParentOnly = props.patchType == nil, isParentOnly = props.patchType == nil,
onSelectionChange = props.onSelectionChange, onSelectionChange = props.onSelectionChange,
onSubtreeSelectionChange = props.onSubtreeSelectionChange, onSubtreeSelectionChange = props.onSubtreeSelectionChange,
onSubtreeHoverStart = function() -- Subtree hover highlight: pass binding and ancestors to child buttons
subtreeHighlightBinding = props.subtreeHighlightNodeId,
ancestorIds = props.ancestorIds,
onSubtreeHoverStart = function(optionType)
if props.setSubtreeHighlightNodeId then if props.setSubtreeHighlightNodeId then
props.setSubtreeHighlightNodeId(props.nodeId) props.setSubtreeHighlightNodeId({ nodeId = props.nodeId, optionType = optionType })
end end
end, end,
onSubtreeHoverEnd = function() onSubtreeHoverEnd = function()

View file

@ -245,7 +245,7 @@ function ConfirmingPage:render()
}), }),
StringDiff = e(StudioPluginGui, { StringDiff = e(StudioPluginGui, {
id = "Rojo_ConfirmingStringDiff", id = "Atlas_ConfirmingStringDiff",
title = "String diff", title = "String diff",
active = self.state.showingStringDiff, active = self.state.showingStringDiff,
isEphemeral = true, isEphemeral = true,
@ -283,7 +283,7 @@ function ConfirmingPage:render()
}), }),
TableDiff = e(StudioPluginGui, { TableDiff = e(StudioPluginGui, {
id = "Rojo_ConfirmingTableDiff", id = "Atlas_ConfirmingTableDiff",
title = "Table diff", title = "Table diff",
active = self.state.showingTableDiff, active = self.state.showingTableDiff,
isEphemeral = true, isEphemeral = true,
@ -322,7 +322,7 @@ function ConfirmingPage:render()
-- Accept confirmation popup for unselected items -- Accept confirmation popup for unselected items
AcceptConfirm = e(StudioPluginGui, { AcceptConfirm = e(StudioPluginGui, {
id = "Rojo_AcceptConfirm", id = "Atlas_AcceptConfirm",
title = "Unreviewed Items", title = "Unreviewed Items",
active = self.state.showingAcceptConfirm, active = self.state.showingAcceptConfirm,
isEphemeral = true, isEphemeral = true,
@ -400,7 +400,7 @@ function ConfirmingPage:render()
if self.props.createPopup then if self.props.createPopup then
return e(StudioPluginGui, { return e(StudioPluginGui, {
id = "Rojo_DiffSync", id = "Atlas_DiffSync",
title = string.format( title = string.format(
"Confirm sync for project '%s':", "Confirm sync for project '%s':",
self.props.confirmData.serverInfo.projectName or "UNKNOWN" self.props.confirmData.serverInfo.projectName or "UNKNOWN"

View file

@ -481,7 +481,7 @@ function ConnectedPage:render()
}), }),
ChangesViewer = e(StudioPluginGui, { ChangesViewer = e(StudioPluginGui, {
id = "Rojo_ChangesViewer", id = "Atlas_ChangesViewer",
title = "View changes", title = "View changes",
active = self.state.renderChanges, active = self.state.renderChanges,
isEphemeral = true, isEphemeral = true,
@ -536,7 +536,7 @@ function ConnectedPage:render()
}), }),
StringDiff = e(StudioPluginGui, { StringDiff = e(StudioPluginGui, {
id = "Rojo_ConnectedStringDiff", id = "Atlas_ConnectedStringDiff",
title = "String diff", title = "String diff",
active = self.state.showingStringDiff, active = self.state.showingStringDiff,
isEphemeral = true, isEphemeral = true,
@ -574,7 +574,7 @@ function ConnectedPage:render()
}), }),
TableDiff = e(StudioPluginGui, { TableDiff = e(StudioPluginGui, {
id = "Rojo_ConnectedTableDiff", id = "Atlas_ConnectedTableDiff",
title = "Table diff", title = "Table diff",
active = self.state.showingTableDiff, active = self.state.showingTableDiff,
isEphemeral = true, isEphemeral = true,

View file

@ -237,7 +237,6 @@ function StudioProvider:updateTheme()
Edit = Color3.fromRGB(255, 0, 255), Edit = Color3.fromRGB(255, 0, 255),
Row = studioTheme:GetColor(Enum.StudioStyleGuideColor.BrightText), Row = studioTheme:GetColor(Enum.StudioStyleGuideColor.BrightText),
SubtreeHighlight = if isDark then Color3.fromRGB(255, 255, 255) else Color3.fromRGB(0, 0, 0),
Warning = studioTheme:GetColor(Enum.StudioStyleGuideColor.WarningText), Warning = studioTheme:GetColor(Enum.StudioStyleGuideColor.WarningText),
WhitespaceOnly = if isDark then Color3.fromRGB(140, 140, 140) else Color3.fromRGB(110, 110, 110), WhitespaceOnly = if isDark then Color3.fromRGB(140, 140, 140) else Color3.fromRGB(110, 110, 110),
Changes = if isDark then Color3.fromRGB(100, 140, 220) else Color3.fromRGB(40, 100, 180), Changes = if isDark then Color3.fromRGB(100, 140, 220) else Color3.fromRGB(40, 100, 180),

View file

@ -63,7 +63,7 @@ function App:init()
self.notifId = 0 self.notifId = 0
self.waypointConnection = ChangeHistoryService.OnUndo:Connect(function(action: string) self.waypointConnection = ChangeHistoryService.OnUndo:Connect(function(action: string)
if not string.find(action, "^Rojo: Patch") then if not string.find(action, "^Atlas: Patch") then
return return
end end
@ -318,7 +318,7 @@ function App:isSyncLockAvailable()
return true return true
end end
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock") local lock = ServerStorage:FindFirstChild("__Atlas_SessionLock")
if not lock then if not lock then
-- No lock is made yet, so it is available -- No lock is made yet, so it is available
return true return true
@ -345,10 +345,10 @@ function App:claimSyncLock()
return false, priorOwner return false, priorOwner
end end
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock") local lock = ServerStorage:FindFirstChild("__Atlas_SessionLock")
if not lock then if not lock then
lock = Instance.new("ObjectValue") lock = Instance.new("ObjectValue")
lock.Name = "__Rojo_SessionLock" lock.Name = "__Atlas_SessionLock"
lock.Archivable = false lock.Archivable = false
lock.Value = Players.LocalPlayer lock.Value = Players.LocalPlayer
lock.Parent = ServerStorage lock.Parent = ServerStorage
@ -362,7 +362,7 @@ function App:claimSyncLock()
end end
function App:releaseSyncLock() function App:releaseSyncLock()
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock") local lock = ServerStorage:FindFirstChild("__Atlas_SessionLock")
if not lock then if not lock then
Log.trace("No sync lock found, assumed released") Log.trace("No sync lock found, assumed released")
return return
@ -450,7 +450,7 @@ function App:checkSyncReminder()
local timeSinceSync = timeUtil.elapsedToText(os.time() - priorSyncInfo.timestamp) local timeSinceSync = timeUtil.elapsedToText(os.time() - priorSyncInfo.timestamp)
self:sendSyncReminder( self:sendSyncReminder(
`You synced project '{priorSyncInfo.projectName}' to this place {timeSinceSync}.\nDid you mean to run 'rojo serve' and then connect?` `You synced project '{priorSyncInfo.projectName}' to this place {timeSinceSync}.\nDid you mean to run 'atlas serve' and then connect?`
) )
end end
end) end)
@ -531,7 +531,7 @@ function App:isAutoConnectPlaytestServerAvailable()
and RunService:IsStudio() and RunService:IsStudio()
and RunService:IsServer() and RunService:IsServer()
and Settings:get("autoConnectPlaytestServer") and Settings:get("autoConnectPlaytestServer")
and workspace:GetAttribute("__Rojo_ConnectionUrl") and workspace:GetAttribute("__Atlas_ConnectionUrl")
end end
function App:isAutoConnectPlaytestServerWriteable() function App:isAutoConnectPlaytestServerWriteable()
@ -544,7 +544,7 @@ function App:setRunningConnectionInfo(baseUrl: string)
end end
Log.trace("Setting connection info for play solo auto-connect") Log.trace("Setting connection info for play solo auto-connect")
workspace:SetAttribute("__Rojo_ConnectionUrl", baseUrl) workspace:SetAttribute("__Atlas_ConnectionUrl", baseUrl)
end end
function App:clearRunningConnectionInfo() function App:clearRunningConnectionInfo()
@ -554,11 +554,11 @@ function App:clearRunningConnectionInfo()
end end
Log.trace("Clearing connection info for play solo auto-connect") Log.trace("Clearing connection info for play solo auto-connect")
workspace:SetAttribute("__Rojo_ConnectionUrl", nil) workspace:SetAttribute("__Atlas_ConnectionUrl", nil)
end end
function App:useRunningConnectionInfo() function App:useRunningConnectionInfo()
local connectionInfo = workspace:GetAttribute("__Rojo_ConnectionUrl") local connectionInfo = workspace:GetAttribute("__Atlas_ConnectionUrl")
if not connectionInfo then if not connectionInfo then
return return
end end
@ -890,7 +890,8 @@ function App:endSession()
-- but the UI is still stuck on Connected/Connecting, force reset to NotConnected. -- but the UI is still stuck on Connected/Connecting, force reset to NotConnected.
-- This handles race conditions where onStatusChanged(Connected) fires after -- This handles race conditions where onStatusChanged(Connected) fires after
-- onStatusChanged(Disconnected) due to a coroutine resuming on a dead session. -- onStatusChanged(Disconnected) due to a coroutine resuming on a dead session.
if self.state.appStatus ~= AppStatus.NotConnected if
self.state.appStatus ~= AppStatus.NotConnected
and self.state.appStatus ~= AppStatus.Error and self.state.appStatus ~= AppStatus.Error
and self.state.appStatus ~= AppStatus.Settings and self.state.appStatus ~= AppStatus.Settings
then then

View file

@ -27,8 +27,8 @@ return strict("Config", {
codename = "Epiphany", codename = "Epiphany",
version = realVersion, version = realVersion,
expectedServerVersionString = ("%d.%d or newer"):format(realVersion[1], realVersion[2]), expectedServerVersionString = ("%d.%d or newer"):format(realVersion[1], realVersion[2]),
protocolVersion = 5, protocolVersion = 6,
defaultHost = "localhost", defaultHost = "localhost",
defaultPort = "34872", defaultPort = "34873",
ignoredClassNames = IgnoredClassNames, ignoredClassNames = IgnoredClassNames,
}) })

View file

@ -38,11 +38,11 @@ Settings._bindings = {}
if plugin then if plugin then
for name, defaultValue in pairs(Settings._values) do for name, defaultValue in pairs(Settings._values) do
local savedValue = plugin:GetSetting("Rojo_" .. name) local savedValue = plugin:GetSetting("Atlas_" .. name)
if savedValue == nil then if savedValue == nil then
-- plugin:SetSetting hits disc instead of memory, so it can be slow. Spawn so we don't hang. -- plugin:SetSetting hits disc instead of memory, so it can be slow. Spawn so we don't hang.
task.spawn(plugin.SetSetting, plugin, "Rojo_" .. name, defaultValue) task.spawn(plugin.SetSetting, plugin, "Atlas_" .. name, defaultValue)
Settings._values[name] = defaultValue Settings._values[name] = defaultValue
else else
Settings._values[name] = savedValue Settings._values[name] = savedValue
@ -67,7 +67,7 @@ function Settings:set(name, value)
if plugin then if plugin then
-- plugin:SetSetting hits disc instead of memory, so it can be slow. Spawn so we don't hang. -- plugin:SetSetting hits disc instead of memory, so it can be slow. Spawn so we don't hang.
task.spawn(plugin.SetSetting, plugin, "Rojo_" .. name, value) task.spawn(plugin.SetSetting, plugin, "Atlas_" .. name, value)
end end
if self._updateListeners[name] then if self._updateListeners[name] then

View file

@ -39,6 +39,7 @@ local ApiInfoResponse = t.interface({
sessionId = t.string, sessionId = t.string,
serverVersion = t.string, serverVersion = t.string,
protocolVersion = t.number, protocolVersion = t.number,
serverFork = t.string,
expectedPlaceIds = t.optional(t.array(t.number)), expectedPlaceIds = t.optional(t.array(t.number)),
rootInstanceId = RbxId, rootInstanceId = RbxId,
}) })

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: add_folder projectName: add_folder
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: edit_init projectName: edit_init
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: empty projectName: empty
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: empty_folder projectName: empty_folder
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(&info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: forced_parent projectName: forced_parent
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(&info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: meshpart projectName: meshpart
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: move_folder_of_stuff projectName: move_folder_of_stuff
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: top-level projectName: top-level
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: no_name_project projectName: no_name_project
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: no_name_top_level_project projectName: no_name_top_level_project
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: pivot_migration projectName: pivot_migration
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: ref_properties projectName: ref_properties
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: ref_properties projectName: ref_properties
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: ref_properties_remove projectName: ref_properties_remove
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: remove_file projectName: remove_file
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: scripts projectName: scripts
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: sync_rule_alone projectName: sync_rule_alone
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: sync_rule_complex projectName: sync_rule_complex
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: sync_rule_no_extension projectName: sync_rule_no_extension
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,8 +4,9 @@ expression: redactions.redacted_yaml(info)
--- ---
ignoreHiddenServices: true ignoreHiddenServices: true
projectName: sync_rule_no_name_project projectName: sync_rule_no_name_project
protocolVersion: 5 protocolVersion: 6
rootInstanceId: id-2 rootInstanceId: id-2
serverFork: atlas
serverVersion: "[server-version]" serverVersion: "[server-version]"
sessionId: id-1 sessionId: id-1
syncSourceOnly: true syncSourceOnly: true

View file

@ -4,7 +4,7 @@
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
Write-Host "Building test place..." -ForegroundColor Cyan Write-Host "Building test place..." -ForegroundColor Cyan
rojo build plugin/test-place.project.json -o TestPlace.rbxl atlas build plugin/test-place.project.json -o TestPlace.rbxl
Write-Host "Running tests in Roblox..." -ForegroundColor Cyan Write-Host "Running tests in Roblox..." -ForegroundColor Cyan
run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl

View file

@ -1,2 +1,2 @@
rojo build plugin/test-place.project.json -o TestPlace.rbxl atlas build plugin/test-place.project.json -o TestPlace.rbxl
run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl

View file

@ -4,4 +4,4 @@
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
Write-Host "Watching for plugin changes... (Ctrl+C to stop)" -ForegroundColor Cyan Write-Host "Watching for plugin changes... (Ctrl+C to stop)" -ForegroundColor Cyan
rojo build plugin.project.json --plugin Rojo.rbxm --watch atlas build plugin.project.json --plugin Atlas.rbxm --watch

View file

@ -1 +1 @@
rojo build plugin.project.json --plugin Rojo.rbxm --watch atlas build plugin.project.json --plugin Atlas.rbxm --watch

View file

@ -23,7 +23,7 @@ impl FmtProjectCommand {
let base_path = resolve_path(&self.project); let base_path = resolve_path(&self.project);
let project = Project::load_fuzzy(&vfs, &base_path)? let project = Project::load_fuzzy(&vfs, &base_path)?
.context("A project file is required to run 'rojo fmt-project'")?; .context("A project file is required to run 'atlas fmt-project'")?;
let serialized = String::from_utf8( let serialized = String::from_utf8(
crate::json::to_vec_pretty_sorted(&project) crate::json::to_vec_pretty_sorted(&project)

View file

@ -203,7 +203,7 @@ impl InitCommand {
println!("Created project successfully."); println!("Created project successfully.");
if self.placeid.is_some() { if self.placeid.is_some() {
println!("Run 'rojo syncback' to sync your place."); println!("Run 'atlas syncback' to sync your place.");
} }
Ok(()) Ok(())

View file

@ -33,7 +33,7 @@ pub use self::upload::UploadCommand;
/// Command line options that Rojo accepts, defined using the clap crate. /// Command line options that Rojo accepts, defined using the clap crate.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[clap(name = "Rojo", version, about)] #[clap(name = "Atlas", version, about)]
pub struct Options { pub struct Options {
#[clap(flatten)] #[clap(flatten)]
pub global: GlobalOptions, pub global: GlobalOptions,

View file

@ -10,7 +10,7 @@ use roblox_install::RobloxStudio;
use crate::serve_session::ServeSession; use crate::serve_session::ServeSession;
static PLUGIN_BINCODE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/plugin.bincode")); static PLUGIN_BINCODE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/plugin.bincode"));
static PLUGIN_FILE_NAME: &str = "RojoManagedPlugin.rbxm"; static PLUGIN_FILE_NAME: &str = "AtlasManagedPlugin.rbxm";
/// Install Rojo's plugin. /// Install Rojo's plugin.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]

View file

@ -12,7 +12,7 @@ use crate::{serve_session::ServeSession, web::LiveServer};
use super::resolve_path; use super::resolve_path;
const DEFAULT_BIND_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); const DEFAULT_BIND_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
const DEFAULT_PORT: u16 = 34872; const DEFAULT_PORT: u16 = 34873;
/// Expose a Rojo project to the Rojo Studio plugin. /// Expose a Rojo project to the Rojo Studio plugin.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -25,7 +25,7 @@ pub struct ServeCommand {
#[clap(long)] #[clap(long)]
pub address: Option<IpAddr>, pub address: Option<IpAddr>,
/// The port to listen on. Defaults to the project's preference, or `34872` if /// The port to listen on. Defaults to the project's preference, or `34873` if
/// it has none. /// it has none.
#[clap(long)] #[clap(long)]
pub port: Option<u16>, pub port: Option<u16>,

View file

@ -32,7 +32,7 @@ impl StudioCommand {
let base_path = resolve_path(&self.project); let base_path = resolve_path(&self.project);
let project = Project::load_fuzzy(&vfs, &base_path)? let project = Project::load_fuzzy(&vfs, &base_path)?
.context("A project file is required to run 'rojo studio'")?; .context("A project file is required to run 'atlas studio'")?;
let serve_place_ids = project let serve_place_ids = project
.serve_place_ids .serve_place_ids

View file

@ -272,6 +272,7 @@ impl ApiService {
msgpack_ok(&ServerInfoResponse { msgpack_ok(&ServerInfoResponse {
server_version: SERVER_VERSION.to_owned(), server_version: SERVER_VERSION.to_owned(),
protocol_version: PROTOCOL_VERSION, protocol_version: PROTOCOL_VERSION,
server_fork: "atlas".to_owned(),
session_id: self.serve_session.session_id(), session_id: self.serve_session.session_id(),
project_name: self.serve_session.project_name().to_owned(), project_name: self.serve_session.project_name().to_owned(),
expected_place_ids: self.serve_session.serve_place_ids().cloned(), expected_place_ids: self.serve_session.serve_place_ids().cloned(),

View file

@ -25,7 +25,7 @@ use crate::{
pub(crate) const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION"); pub(crate) const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
/// Current protocol version, which is required to match. /// Current protocol version, which is required to match.
pub const PROTOCOL_VERSION: u64 = 5; pub const PROTOCOL_VERSION: u64 = 6;
/// Message returned by Rojo API when a change has occurred. /// Message returned by Rojo API when a change has occurred.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -159,6 +159,7 @@ pub struct ServerInfoResponse {
pub session_id: SessionId, pub session_id: SessionId,
pub server_version: String, pub server_version: String,
pub protocol_version: u64, pub protocol_version: u64,
pub server_fork: String,
pub project_name: String, pub project_name: String,
#[serde( #[serde(
serialize_with = "serialize_place_ids", serialize_with = "serialize_place_ids",

View file

@ -7,7 +7,7 @@ use std::{
use walkdir::WalkDir; use walkdir::WalkDir;
pub static ROJO_PATH: &str = env!("CARGO_BIN_EXE_rojo"); pub static ROJO_PATH: &str = env!("CARGO_BIN_EXE_atlas");
pub static BUILD_TESTS_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/rojo-test/build-tests"); pub static BUILD_TESTS_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/rojo-test/build-tests");
pub static SERVE_TESTS_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/rojo-test/serve-tests"); pub static SERVE_TESTS_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/rojo-test/serve-tests");
pub static SYNCBACK_TESTS_PATH: &str = pub static SYNCBACK_TESTS_PATH: &str =

@ -1 +1 @@
Subproject commit 661301ed0ceff950c4fdeac4df332d38a2f89757 Subproject commit bc0d6f803f75820d71c04be989be5dc0fb34b68e