forked from rojo-rbx/rojo
Compare commits
24 Commits
aarch-wind
...
v7.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ddbefa88f | ||
|
|
d935115591 | ||
|
|
bd2ea42732 | ||
|
|
3bac38ee34 | ||
|
|
a7a4f6d8f2 | ||
|
|
80b6facbd3 | ||
|
|
7dee898400 | ||
|
|
4c4b2dbe17 | ||
|
|
73ed5ae697 | ||
|
|
833320de64 | ||
|
|
0d6ff8ef8a | ||
|
|
55a207a275 | ||
|
|
f33d1f1cc4 | ||
|
|
19ca2b12fc | ||
|
|
b7d3394464 | ||
|
|
8c33100d7a | ||
|
|
80c406f196 | ||
|
|
bc2c76e5e2 | ||
|
|
4a7bddbc09 | ||
|
|
e316fdbaef | ||
|
|
34106f470f | ||
|
|
d9ab0e7de8 | ||
|
|
5ca1573e2e | ||
|
|
c9ce996626 |
2
.dir-locals.el
Normal file
2
.dir-locals.el
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
((nil . ((eglot-luau-rojo-project-path . "plugin.project.json")
|
||||||
|
(eglot-luau-rojo-sourcemap-enabled . 't))))
|
||||||
2
.github/workflows/changelog.yml
vendored
2
.github/workflows/changelog.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
name: Check Actions
|
name: Check Actions
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Changelog check
|
- name: Changelog check
|
||||||
uses: Zomzog/changelog-checker@v1.3.0
|
uses: Zomzog/changelog-checker@v1.3.0
|
||||||
|
|||||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -30,9 +30,9 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Setup Aftman
|
- name: Setup Aftman
|
||||||
uses: ok-nick/setup-aftman@v0.3.0
|
uses: ok-nick/setup-aftman@v0.4.2
|
||||||
with:
|
with:
|
||||||
version: 'v0.2.7'
|
version: 'v0.3.0'
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --locked --verbose
|
run: cargo build --locked --verbose
|
||||||
@@ -56,9 +56,9 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Setup Aftman
|
- name: Setup Aftman
|
||||||
uses: ok-nick/setup-aftman@v0.3.0
|
uses: ok-nick/setup-aftman@v0.4.2
|
||||||
with:
|
with:
|
||||||
version: 'v0.2.7'
|
version: 'v0.3.0'
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --locked --verbose
|
run: cargo build --locked --verbose
|
||||||
@@ -81,9 +81,9 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Setup Aftman
|
- name: Setup Aftman
|
||||||
uses: ok-nick/setup-aftman@v0.3.0
|
uses: ok-nick/setup-aftman@v0.4.2
|
||||||
with:
|
with:
|
||||||
version: 'v0.2.7'
|
version: 'v0.3.0'
|
||||||
|
|
||||||
- name: Stylua
|
- name: Stylua
|
||||||
run: stylua --check plugin/src
|
run: stylua --check plugin/src
|
||||||
|
|||||||
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -26,14 +26,12 @@ jobs:
|
|||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Setup Aftman
|
- name: Setup Aftman
|
||||||
uses: ok-nick/setup-aftman@v0.1.0
|
uses: ok-nick/setup-aftman@v0.4.2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
version: 'v0.3.0'
|
||||||
trust-check: false
|
|
||||||
version: 'v0.2.6'
|
|
||||||
|
|
||||||
- name: Build Plugin
|
- name: Build Plugin
|
||||||
run: rojo build plugin --output Rojo.rbxm
|
run: rojo build plugin.project.json --output Rojo.rbxm
|
||||||
|
|
||||||
- name: Upload Plugin to Release
|
- name: Upload Plugin to Release
|
||||||
env:
|
env:
|
||||||
@@ -55,7 +53,7 @@ jobs:
|
|||||||
# https://doc.rust-lang.org/rustc/platform-support.html
|
# https://doc.rust-lang.org/rustc/platform-support.html
|
||||||
include:
|
include:
|
||||||
- host: linux
|
- host: linux
|
||||||
os: ubuntu-20.04
|
os: ubuntu-latest
|
||||||
target: x86_64-unknown-linux-gnu
|
target: x86_64-unknown-linux-gnu
|
||||||
label: linux-x86_64
|
label: linux-x86_64
|
||||||
|
|
||||||
@@ -89,11 +87,9 @@ jobs:
|
|||||||
targets: ${{ matrix.target }}
|
targets: ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Setup Aftman
|
- name: Setup Aftman
|
||||||
uses: ok-nick/setup-aftman@v0.1.0
|
uses: ok-nick/setup-aftman@v0.4.2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
version: 'v0.3.0'
|
||||||
trust-check: false
|
|
||||||
version: 'v0.2.6'
|
|
||||||
|
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
run: cargo build --release --locked --verbose --target ${{ matrix.target }}
|
run: cargo build --release --locked --verbose --target ${{ matrix.target }}
|
||||||
|
|||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -10,8 +10,8 @@
|
|||||||
/*.rbxl
|
/*.rbxl
|
||||||
/*.rbxlx
|
/*.rbxlx
|
||||||
|
|
||||||
# Test places for the Roblox Studio Plugin
|
# Sourcemap for the Rojo plugin (for better intellisense)
|
||||||
/plugin/*.rbxlx
|
/sourcemap.json
|
||||||
|
|
||||||
# Roblox Studio holds 'lock' files on places
|
# Roblox Studio holds 'lock' files on places
|
||||||
*.rbxl.lock
|
*.rbxl.lock
|
||||||
@@ -19,3 +19,7 @@
|
|||||||
|
|
||||||
# Snapshot files from the 'insta' Rust crate
|
# Snapshot files from the 'insta' Rust crate
|
||||||
**/*.snap.new
|
**/*.snap.new
|
||||||
|
|
||||||
|
# Macos file system junk
|
||||||
|
._*
|
||||||
|
.DS_STORE
|
||||||
|
|||||||
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"JohnnyMorganz.luau-lsp",
|
||||||
|
"JohnnyMorganz.stylua",
|
||||||
|
"Kampfkarren.selene-vscode",
|
||||||
|
"rust-lang.rust-analyzer"
|
||||||
|
]
|
||||||
|
}
|
||||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"luau-lsp.sourcemap.rojoProjectFile": "plugin.project.json",
|
||||||
|
"luau-lsp.sourcemap.autogenerate": true
|
||||||
|
}
|
||||||
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,6 +1,14 @@
|
|||||||
# Rojo Changelog
|
# Rojo Changelog
|
||||||
|
|
||||||
## Unreleased Changes
|
## 7.5.0 - April 25th, 2025
|
||||||
|
* Fixed an edge case that caused model pivots to not be built correctly in some cases ([#1027])
|
||||||
|
* Add `blockedPlaceIds` project config field to allow blocking place ids from being live synced ([#1021])
|
||||||
|
* Adds support for `.plugin.lua(u)` files - this applies the `Plugin` RunContext. ([#1008])
|
||||||
|
* Added support for Roblox's `Content` type. This replaces the old `Content` type with `ContentId` to reflect Roblox's change.
|
||||||
|
If you were previously using the fully-qualified syntax for `Content` you will need to switch it to `ContentId`.
|
||||||
|
* Added support for `Enum` attributes
|
||||||
|
* Significantly improved performance of `.rbxm` parsing
|
||||||
|
* Support for a `$schema` field in all special JSON files (`.project.json`, `.model.json`, and `.meta.json`) ([#974])
|
||||||
* Projects may now manually link `Ref` properties together using `Attributes`. ([#843])
|
* Projects may now manually link `Ref` properties together using `Attributes`. ([#843])
|
||||||
This has two parts: using `id` or `$id` in JSON files or a `Rojo_Target` attribute, an Instance
|
This has two parts: using `id` or `$id` in JSON files or a `Rojo_Target` attribute, an Instance
|
||||||
is given an ID. Then, that ID may be used elsewhere in the project to point to an Instance
|
is given an ID. Then, that ID may be used elsewhere in the project to point to an Instance
|
||||||
@@ -28,6 +36,8 @@
|
|||||||
* Added experimental setting for Auto Connect in playtests ([#840])
|
* Added experimental setting for Auto Connect in playtests ([#840])
|
||||||
* Improved settings UI ([#886])
|
* Improved settings UI ([#886])
|
||||||
* `Open Scripts Externally` option can now be changed while syncing ([#911])
|
* `Open Scripts Externally` option can now be changed while syncing ([#911])
|
||||||
|
* The sync reminder notification will now tell you what was last synced and when ([#987])
|
||||||
|
* Fixed notification and tooltip text sometimes getting cut off ([#988])
|
||||||
* Projects may now specify rules for syncing files as if they had a different file extension. ([#813])
|
* Projects may now specify rules for syncing files as if they had a different file extension. ([#813])
|
||||||
This is specified via a new field on project files, `syncRules`:
|
This is specified via a new field on project files, `syncRules`:
|
||||||
|
|
||||||
@@ -56,7 +66,7 @@
|
|||||||
|
|
||||||
Additionally, the `exclude` field allows files to be excluded from the sync rule if they match a pattern specified by it. If it's not present, all files that match `pattern` will be modified using the sync rule.
|
Additionally, the `exclude` field allows files to be excluded from the sync rule if they match a pattern specified by it. If it's not present, all files that match `pattern` will be modified using the sync rule.
|
||||||
|
|
||||||
The `use` field corresponds to one of the potential file type that Rojo will currently include in a project. Files that match the provided pattern will be treated as if they had the file extension for that file type. A full list is below:
|
The `use` field corresponds to one of the potential file type that Rojo will currently include in a project. Files that match the provided pattern will be treated as if they had the file extension for that file type.
|
||||||
|
|
||||||
| `use` value | file extension |
|
| `use` value | file extension |
|
||||||
|:---------------|:----------------|
|
|:---------------|:----------------|
|
||||||
@@ -73,6 +83,16 @@
|
|||||||
| `project` | `.project.json` |
|
| `project` | `.project.json` |
|
||||||
| `ignore` | None! |
|
| `ignore` | None! |
|
||||||
|
|
||||||
|
Additionally, there are `use` values for specific script types ([#909]):
|
||||||
|
|
||||||
|
| `use` value | script type |
|
||||||
|
|:-------------------------|:---------------------------------------|
|
||||||
|
| `legacyServerScript` | `Script` with `Enum.RunContext.Legacy` |
|
||||||
|
| `legacyClientScript` | `LocalScript` |
|
||||||
|
| `runContextServerScript` | `Script` with `Enum.RunContext.Server` |
|
||||||
|
| `runContextClientScript` | `Script` with `Enum.RunContext.Client` |
|
||||||
|
| `pluginScript` | `Script` with `Enum.RunContext.Plugin` |
|
||||||
|
|
||||||
**All** sync rules are reset between project files, so they must be specified in each one when nesting them. This is to ensure that nothing can break other projects by changing how files are synced!
|
**All** sync rules are reset between project files, so they must be specified in each one when nesting them. This is to ensure that nothing can break other projects by changing how files are synced!
|
||||||
|
|
||||||
[#813]: https://github.com/rojo-rbx/rojo/pull/813
|
[#813]: https://github.com/rojo-rbx/rojo/pull/813
|
||||||
@@ -83,8 +103,19 @@
|
|||||||
[#843]: https://github.com/rojo-rbx/rojo/pull/843
|
[#843]: https://github.com/rojo-rbx/rojo/pull/843
|
||||||
[#883]: https://github.com/rojo-rbx/rojo/pull/883
|
[#883]: https://github.com/rojo-rbx/rojo/pull/883
|
||||||
[#886]: https://github.com/rojo-rbx/rojo/pull/886
|
[#886]: https://github.com/rojo-rbx/rojo/pull/886
|
||||||
|
[#909]: https://github.com/rojo-rbx/rojo/pull/909
|
||||||
[#911]: https://github.com/rojo-rbx/rojo/pull/911
|
[#911]: https://github.com/rojo-rbx/rojo/pull/911
|
||||||
[#915]: https://github.com/rojo-rbx/rojo/pull/915
|
[#915]: https://github.com/rojo-rbx/rojo/pull/915
|
||||||
|
[#974]: https://github.com/rojo-rbx/rojo/pull/974
|
||||||
|
[#987]: https://github.com/rojo-rbx/rojo/pull/987
|
||||||
|
[#988]: https://github.com/rojo-rbx/rojo/pull/988
|
||||||
|
[#1008]: https://github.com/rojo-rbx/rojo/pull/1008
|
||||||
|
[#1021]: https://github.com/rojo-rbx/rojo/pull/1021
|
||||||
|
[#1027]: https://github.com/rojo-rbx/rojo/pull/1027
|
||||||
|
|
||||||
|
## [7.4.4] - August 22nd, 2024
|
||||||
|
* Fixed issue with reading attributes from `Lighting` in new place files
|
||||||
|
* `Instance.Archivable` will now default to `true` when building a project into a binary (`rbxm`/`rbxl`) file rather than `false`.
|
||||||
|
|
||||||
## [7.4.3] - August 6th, 2024
|
## [7.4.3] - August 6th, 2024
|
||||||
* Fixed issue with building binary files introduced in 7.4.2
|
* Fixed issue with building binary files introduced in 7.4.2
|
||||||
|
|||||||
@@ -16,6 +16,23 @@ You'll want these tools to work on Rojo:
|
|||||||
* Latest stable Rust compiler
|
* Latest stable Rust compiler
|
||||||
* Latest stable [Rojo](https://github.com/rojo-rbx/rojo)
|
* Latest stable [Rojo](https://github.com/rojo-rbx/rojo)
|
||||||
* [Foreman](https://github.com/Roblox/foreman)
|
* [Foreman](https://github.com/Roblox/foreman)
|
||||||
|
* [Luau Language Server](https://github.com/JohnnyMorganz/luau-lsp) (Only needed if working on the Studio plugin.)
|
||||||
|
|
||||||
|
When working on the Studio plugin, we recommend using this command to automatically rebuild the plugin when you save a change:
|
||||||
|
|
||||||
|
*(Make sure you've enabled the Studio setting to reload plugins on file change!)*
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/watch-build-plugin.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also run the plugin's unit tests with the following:
|
||||||
|
|
||||||
|
*(Make sure you have `run-in-roblox` installed first!)*
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/unit-test-plugin.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
Documentation impacts way more people than the individual lines of code we write.
|
Documentation impacts way more people than the individual lines of code we write.
|
||||||
|
|||||||
180
Cargo.lock
generated
180
Cargo.lock
generated
@@ -17,6 +17,19 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"getrandom",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -171,6 +184,10 @@ name = "cc"
|
|||||||
version = "1.0.89"
|
version = "1.0.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
|
checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
|
||||||
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -492,7 +509,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall 0.4.1",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -935,6 +952,15 @@ version = "1.0.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jod-thread"
|
name = "jod-thread"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -962,9 +988,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazycell"
|
name = "lazycell"
|
||||||
@@ -986,7 +1012,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall 0.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1001,6 +1027,16 @@ version = "0.4.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.21"
|
version = "0.4.21"
|
||||||
@@ -1241,6 +1277,29 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall 0.5.10",
|
||||||
|
"smallvec",
|
||||||
|
"windows-targets 0.52.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@@ -1310,6 +1369,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plotters"
|
name = "plotters"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@@ -1498,10 +1563,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_binary"
|
name = "rbx_binary"
|
||||||
version = "0.7.7"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b85057e8ff75a1ce99248200c4b3c7b481a3d52f921f1053ecd67921dcc7930"
|
checksum = "9573fee5e073d7b303f475c285197fdc8179468de66ca60ee115a58fbac99296"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"log",
|
"log",
|
||||||
"lz4",
|
"lz4",
|
||||||
"profiling",
|
"profiling",
|
||||||
@@ -1509,23 +1575,26 @@ dependencies = [
|
|||||||
"rbx_reflection",
|
"rbx_reflection",
|
||||||
"rbx_reflection_database",
|
"rbx_reflection_database",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"zstd",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_dom_weak"
|
name = "rbx_dom_weak"
|
||||||
version = "2.9.0"
|
version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcd2a17d09e46af0805f8b311a926402172b97e8d9388745c9adf8f448901841"
|
checksum = "04425cf6e9376e5486f4fb35906c120d1b1b45618a490318cf563fab1fa230a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"rbx_types",
|
"rbx_types",
|
||||||
"serde",
|
"serde",
|
||||||
|
"ustr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_reflection"
|
name = "rbx_reflection"
|
||||||
version = "4.7.0"
|
version = "5.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8118ac6021d700e8debe324af6b40ecfd2cef270a00247849dbdfeebb0802677"
|
checksum = "1b6d0d62baa613556b058a5f94a53b01cf0ccde0ea327ce03056e335b982e77e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rbx_types",
|
"rbx_types",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1534,9 +1603,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_reflection_database"
|
name = "rbx_reflection_database"
|
||||||
version = "0.2.12+roblox-638"
|
version = "1.0.2+roblox-670"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e29381d675420e841f8c02db5755cbb2545ed3e13f56c539546dc58702b512a"
|
checksum = "5349b19e5e94fbcaba7a52175263ab64011e0a13f17ff57729f2f560ccdec615"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"rbx_reflection",
|
"rbx_reflection",
|
||||||
@@ -1546,9 +1615,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_types"
|
name = "rbx_types"
|
||||||
version = "1.10.0"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e30f49b2a3bb667e4074ba73c2dfb8ca0873f610b448ccf318a240acfdec6c73"
|
checksum = "78e4fdde46493def107e5f923d82e813dec9b3eef52c2f75fbad3a716023eda2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
@@ -1561,10 +1630,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_xml"
|
name = "rbx_xml"
|
||||||
version = "0.13.5"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b14b3027bc9ccd82e2fc854c8bcd25ed58318e570c355bf2cf63df9cdbd5ba8"
|
checksum = "bb623833c31cc43bbdaeb32f5e91db8ecd63fc46e438d0d268baf9e61539cf1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
"log",
|
"log",
|
||||||
"rbx_dom_weak",
|
"rbx_dom_weak",
|
||||||
@@ -1582,6 +1652,15 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@@ -1752,7 +1831,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "7.4.0"
|
version = "7.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
@@ -1896,6 +1975,12 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sct"
|
name = "sct"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -2393,6 +2478,19 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ustr"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "18b19e258aa08450f93369cf56dd78063586adf19e92a75b338a800f799a0208"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"parking_lot",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
@@ -2784,3 +2882,51 @@ name = "yansi"
|
|||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.78",
|
||||||
|
"quote 1.0.35",
|
||||||
|
"syn 2.0.52",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-safe",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-safe"
|
||||||
|
version = "7.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-sys"
|
||||||
|
version = "2.0.15+zstd.1.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|||||||
13
Cargo.toml
13
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "7.4.0"
|
version = "7.5.0"
|
||||||
rust-version = "1.70.0"
|
rust-version = "1.70.0"
|
||||||
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
||||||
description = "Enables professional-grade development tools for Roblox developers"
|
description = "Enables professional-grade development tools for Roblox developers"
|
||||||
@@ -51,11 +51,11 @@ memofs = { version = "0.3.0", path = "crates/memofs" }
|
|||||||
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
|
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
|
||||||
# rbx_xml = { path = "../rbx-dom/rbx_xml" }
|
# rbx_xml = { path = "../rbx-dom/rbx_xml" }
|
||||||
|
|
||||||
rbx_binary = "0.7.7"
|
rbx_binary = "1.0.0"
|
||||||
rbx_dom_weak = "2.9.0"
|
rbx_dom_weak = "3.0.0"
|
||||||
rbx_reflection = "4.7.0"
|
rbx_reflection = "5.0.0"
|
||||||
rbx_reflection_database = "0.2.12"
|
rbx_reflection_database = "1.0.2"
|
||||||
rbx_xml = "0.13.5"
|
rbx_xml = "1.0.0"
|
||||||
|
|
||||||
anyhow = "1.0.80"
|
anyhow = "1.0.80"
|
||||||
backtrace = "0.3.69"
|
backtrace = "0.3.69"
|
||||||
@@ -70,7 +70,6 @@ humantime = "2.1.0"
|
|||||||
hyper = { version = "0.14.28", features = ["server", "tcp", "http1"] }
|
hyper = { version = "0.14.28", features = ["server", "tcp", "http1"] }
|
||||||
jod-thread = "0.1.2"
|
jod-thread = "0.1.2"
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
maplit = "1.0.2"
|
|
||||||
num_cpus = "1.16.0"
|
num_cpus = "1.16.0"
|
||||||
opener = "0.5.2"
|
opener = "0.5.2"
|
||||||
rayon = "1.9.0"
|
rayon = "1.9.0"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[tools]
|
[tools]
|
||||||
rojo = "rojo-rbx/rojo@7.3.0"
|
rojo = "rojo-rbx/rojo@7.4.1"
|
||||||
selene = "Kampfkarren/selene@0.26.1"
|
selene = "Kampfkarren/selene@0.27.1"
|
||||||
stylua = "JohnnyMorganz/stylua@0.18.2"
|
stylua = "JohnnyMorganz/stylua@0.20.0"
|
||||||
run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0"
|
run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0"
|
||||||
|
|||||||
28
build.rs
28
build.rs
@@ -20,6 +20,10 @@ fn snapshot_from_fs_path(path: &Path) -> io::Result<VfsSnapshot> {
|
|||||||
|
|
||||||
let file_name = entry.file_name().to_str().unwrap().to_owned();
|
let file_name = entry.file_name().to_str().unwrap().to_owned();
|
||||||
|
|
||||||
|
if file_name.starts_with(".git") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// We can skip any TestEZ test files since they aren't necessary for
|
// We can skip any TestEZ test files since they aren't necessary for
|
||||||
// the plugin to run.
|
// the plugin to run.
|
||||||
if file_name.ends_with(".spec.lua") || file_name.ends_with(".spec.luau") {
|
if file_name.ends_with(".spec.lua") || file_name.ends_with(".spec.luau") {
|
||||||
@@ -41,12 +45,12 @@ fn snapshot_from_fs_path(path: &Path) -> io::Result<VfsSnapshot> {
|
|||||||
fn main() -> Result<(), anyhow::Error> {
|
fn main() -> Result<(), anyhow::Error> {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
let root_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
|
let root_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
|
||||||
let plugin_root = PathBuf::from(root_dir).join("plugin");
|
let plugin_dir = root_dir.join("plugin");
|
||||||
|
|
||||||
let our_version = Version::parse(env::var_os("CARGO_PKG_VERSION").unwrap().to_str().unwrap())?;
|
let our_version = Version::parse(env::var_os("CARGO_PKG_VERSION").unwrap().to_str().unwrap())?;
|
||||||
let plugin_version =
|
let plugin_version =
|
||||||
Version::parse(fs::read_to_string(plugin_root.join("Version.txt"))?.trim())?;
|
Version::parse(fs::read_to_string(plugin_dir.join("Version.txt"))?.trim())?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
our_version, plugin_version,
|
our_version, plugin_version,
|
||||||
@@ -54,14 +58,16 @@ fn main() -> Result<(), anyhow::Error> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let snapshot = VfsSnapshot::dir(hashmap! {
|
let snapshot = VfsSnapshot::dir(hashmap! {
|
||||||
"default.project.json" => snapshot_from_fs_path(&plugin_root.join("default.project.json"))?,
|
"default.project.json" => snapshot_from_fs_path(&root_dir.join("plugin.project.json"))?,
|
||||||
"fmt" => snapshot_from_fs_path(&plugin_root.join("fmt"))?,
|
"plugin" => VfsSnapshot::dir(hashmap! {
|
||||||
"http" => snapshot_from_fs_path(&plugin_root.join("http"))?,
|
"fmt" => snapshot_from_fs_path(&plugin_dir.join("fmt"))?,
|
||||||
"log" => snapshot_from_fs_path(&plugin_root.join("log"))?,
|
"http" => snapshot_from_fs_path(&plugin_dir.join("http"))?,
|
||||||
"rbx_dom_lua" => snapshot_from_fs_path(&plugin_root.join("rbx_dom_lua"))?,
|
"log" => snapshot_from_fs_path(&plugin_dir.join("log"))?,
|
||||||
"src" => snapshot_from_fs_path(&plugin_root.join("src"))?,
|
"rbx_dom_lua" => snapshot_from_fs_path(&plugin_dir.join("rbx_dom_lua"))?,
|
||||||
"Packages" => snapshot_from_fs_path(&plugin_root.join("Packages"))?,
|
"src" => snapshot_from_fs_path(&plugin_dir.join("src"))?,
|
||||||
"Version.txt" => snapshot_from_fs_path(&plugin_root.join("Version.txt"))?,
|
"Packages" => snapshot_from_fs_path(&plugin_dir.join("Packages"))?,
|
||||||
|
"Version.txt" => snapshot_from_fs_path(&plugin_dir.join("Version.txt"))?,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
let out_path = Path::new(&out_dir).join("plugin.bincode");
|
let out_path = Path::new(&out_dir).join("plugin.bincode");
|
||||||
|
|||||||
@@ -5,19 +5,13 @@ use serde::Serialize;
|
|||||||
/// Enables redacting any value that serializes as a string.
|
/// Enables redacting any value that serializes as a string.
|
||||||
///
|
///
|
||||||
/// Used for transforming Rojo instance IDs into something deterministic.
|
/// Used for transforming Rojo instance IDs into something deterministic.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct RedactionMap {
|
pub struct RedactionMap {
|
||||||
ids: HashMap<String, usize>,
|
ids: HashMap<String, usize>,
|
||||||
last_id: usize,
|
last_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedactionMap {
|
impl RedactionMap {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
ids: HashMap::new(),
|
|
||||||
last_id: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_redacted_value(&self, id: impl ToString) -> Option<String> {
|
pub fn get_redacted_value(&self, id: impl ToString) -> Option<String> {
|
||||||
let id = id.to_string();
|
let id = id.to_string();
|
||||||
|
|
||||||
|
|||||||
@@ -3,25 +3,25 @@
|
|||||||
"tree": {
|
"tree": {
|
||||||
"$className": "Folder",
|
"$className": "Folder",
|
||||||
"Plugin": {
|
"Plugin": {
|
||||||
"$path": "src"
|
"$path": "plugin/src"
|
||||||
},
|
},
|
||||||
"Packages": {
|
"Packages": {
|
||||||
"$path": "Packages",
|
"$path": "plugin/Packages",
|
||||||
"Log": {
|
"Log": {
|
||||||
"$path": "log"
|
"$path": "plugin/log"
|
||||||
},
|
},
|
||||||
"Http": {
|
"Http": {
|
||||||
"$path": "http"
|
"$path": "plugin/http"
|
||||||
},
|
},
|
||||||
"Fmt": {
|
"Fmt": {
|
||||||
"$path": "fmt"
|
"$path": "plugin/fmt"
|
||||||
},
|
},
|
||||||
"RbxDom": {
|
"RbxDom": {
|
||||||
"$path": "rbx_dom_lua"
|
"$path": "plugin/rbx_dom_lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Version": {
|
"Version": {
|
||||||
"$path": "Version.txt"
|
"$path": "plugin/Version.txt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
7.4.0
|
7.5.0
|
||||||
@@ -188,6 +188,38 @@ types = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Content = {
|
Content = {
|
||||||
|
fromPod = function(pod): Content
|
||||||
|
if type(pod) == "string" then
|
||||||
|
if pod == "None" then
|
||||||
|
return Content.none
|
||||||
|
else
|
||||||
|
error(`unexpected Content value '{pod}'`)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local ty, value = next(pod)
|
||||||
|
if ty == "Uri" then
|
||||||
|
return Content.fromUri(value)
|
||||||
|
elseif ty == "Object" then
|
||||||
|
error("Object deserializing is not currently implemented")
|
||||||
|
else
|
||||||
|
error(`Unknown Content type '{ty}' (could not deserialize)`)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
toPod = function(roblox: Content)
|
||||||
|
if roblox.SourceType == Enum.ContentSourceType.None then
|
||||||
|
return "None"
|
||||||
|
elseif roblox.SourceType == Enum.ContentSourceType.Uri then
|
||||||
|
return { Uri = roblox.Uri }
|
||||||
|
elseif roblox.SourceType == Enum.ContentSourceType.Object then
|
||||||
|
error("Object serializing is not currently implemented")
|
||||||
|
else
|
||||||
|
error(`Unknown Content type '{roblox.SourceType} (could not serialize)`)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
|
||||||
|
ContentId = {
|
||||||
fromPod = identity,
|
fromPod = identity,
|
||||||
toPod = identity,
|
toPod = identity,
|
||||||
},
|
},
|
||||||
@@ -205,6 +237,19 @@ types = {
|
|||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
EnumItem = {
|
||||||
|
fromPod = function(pod)
|
||||||
|
return Enum[pod.type]:FromValue(pod.value)
|
||||||
|
end,
|
||||||
|
|
||||||
|
toPod = function(roblox)
|
||||||
|
return {
|
||||||
|
type = tostring(roblox.EnumType),
|
||||||
|
value = roblox.Value,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
|
||||||
Faces = {
|
Faces = {
|
||||||
fromPod = function(pod)
|
fromPod = function(pod)
|
||||||
local faces = {}
|
local faces = {}
|
||||||
@@ -300,7 +345,12 @@ types = {
|
|||||||
local keypoints = {}
|
local keypoints = {}
|
||||||
|
|
||||||
for index, keypoint in ipairs(pod.keypoints) do
|
for index, keypoint in ipairs(pod.keypoints) do
|
||||||
keypoints[index] = NumberSequenceKeypoint.new(keypoint.time, keypoint.value, keypoint.envelope)
|
-- TODO: Add a test for NaN or Infinity values and envelopes
|
||||||
|
-- Right now it isn't possible because it'd fail the roundtrip.
|
||||||
|
-- It's more important that it works right now, though.
|
||||||
|
local value = keypoint.value or 0
|
||||||
|
local envelope = keypoint.envelope or 0
|
||||||
|
keypoints[index] = NumberSequenceKeypoint.new(keypoint.time, value, envelope)
|
||||||
end
|
end
|
||||||
|
|
||||||
return NumberSequence.new(keypoints)
|
return NumberSequence.new(keypoints)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Error.Kind = {
|
|||||||
UnknownProperty = "UnknownProperty",
|
UnknownProperty = "UnknownProperty",
|
||||||
PropertyNotReadable = "PropertyNotReadable",
|
PropertyNotReadable = "PropertyNotReadable",
|
||||||
PropertyNotWritable = "PropertyNotWritable",
|
PropertyNotWritable = "PropertyNotWritable",
|
||||||
|
CannotParseBinaryString = "CannotParseBinaryString",
|
||||||
Roblox = "Roblox",
|
Roblox = "Roblox",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
0.0
|
0.0
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"TestEnumItem": {
|
||||||
|
"EnumItem": {
|
||||||
|
"type": "Material",
|
||||||
|
"value": 256
|
||||||
|
}
|
||||||
|
},
|
||||||
"TestNumber": {
|
"TestNumber": {
|
||||||
"Float64": 1337.0
|
"Float64": 1337.0
|
||||||
},
|
},
|
||||||
@@ -170,9 +176,23 @@
|
|||||||
},
|
},
|
||||||
"ty": "ColorSequence"
|
"ty": "ColorSequence"
|
||||||
},
|
},
|
||||||
"Content": {
|
"ContentId": {
|
||||||
"value": {
|
"value": {
|
||||||
"Content": "rbxassetid://12345"
|
"ContentId": "rbxassetid://12345"
|
||||||
|
},
|
||||||
|
"ty": "ContentId"
|
||||||
|
},
|
||||||
|
"Content_None": {
|
||||||
|
"value": {
|
||||||
|
"Content": "None"
|
||||||
|
},
|
||||||
|
"ty": "Content"
|
||||||
|
},
|
||||||
|
"Content_Uri": {
|
||||||
|
"value": {
|
||||||
|
"Content": {
|
||||||
|
"Uri": "rbxasset://abc/123.rojo"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ty": "Content"
|
"ty": "Content"
|
||||||
},
|
},
|
||||||
@@ -182,6 +202,15 @@
|
|||||||
},
|
},
|
||||||
"ty": "Enum"
|
"ty": "Enum"
|
||||||
},
|
},
|
||||||
|
"EnumItem": {
|
||||||
|
"value": {
|
||||||
|
"EnumItem": {
|
||||||
|
"type": "Material",
|
||||||
|
"value": 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ty": "EnumItem"
|
||||||
|
},
|
||||||
"Faces": {
|
"Faces": {
|
||||||
"value": {
|
"value": {
|
||||||
"Faces": [
|
"Faces": [
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
local CollectionService = game:GetService("CollectionService")
|
local CollectionService = game:GetService("CollectionService")
|
||||||
local ScriptEditorService = game:GetService("ScriptEditorService")
|
local ScriptEditorService = game:GetService("ScriptEditorService")
|
||||||
|
|
||||||
|
local Error = require(script.Parent.Error)
|
||||||
|
|
||||||
--- A list of `Enum.Material` values that are used for Terrain.MaterialColors
|
--- A list of `Enum.Material` values that are used for Terrain.MaterialColors
|
||||||
local TERRAIN_MATERIAL_COLORS = {
|
local TERRAIN_MATERIAL_COLORS = {
|
||||||
Enum.Material.Grass,
|
Enum.Material.Grass,
|
||||||
@@ -51,6 +53,10 @@ return {
|
|||||||
return true, instance:GetAttributes()
|
return true, instance:GetAttributes()
|
||||||
end,
|
end,
|
||||||
write = function(instance, _, value)
|
write = function(instance, _, value)
|
||||||
|
if typeof(value) ~= "table" then
|
||||||
|
return false, Error.new(Error.Kind.CannotParseBinaryString)
|
||||||
|
end
|
||||||
|
|
||||||
local existing = instance:GetAttributes()
|
local existing = instance:GetAttributes()
|
||||||
local didAllWritesSucceed = true
|
local didAllWritesSucceed = true
|
||||||
|
|
||||||
@@ -160,9 +166,14 @@ return {
|
|||||||
return true, colors
|
return true, colors
|
||||||
end,
|
end,
|
||||||
write = function(instance: Terrain, _, value: { [Enum.Material]: Color3 })
|
write = function(instance: Terrain, _, value: { [Enum.Material]: Color3 })
|
||||||
|
if typeof(value) ~= "table" then
|
||||||
|
return false, Error.new(Error.Kind.CannotParseBinaryString)
|
||||||
|
end
|
||||||
|
|
||||||
for material, color in value do
|
for material, color in value do
|
||||||
instance:SetMaterialColor(material, color)
|
instance:SetMaterialColor(material, color)
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
|
||||||
local TestEZ = require(ReplicatedStorage.Packages.TestEZ)
|
local TestEZ = require(ReplicatedStorage.Packages:WaitForChild("TestEZ", 10))
|
||||||
|
|
||||||
local Rojo = ReplicatedStorage.Rojo
|
local Rojo = ReplicatedStorage.Rojo
|
||||||
|
|
||||||
|
|||||||
@@ -45,14 +45,7 @@ end
|
|||||||
|
|
||||||
local function rejectWrongPlaceId(infoResponseBody)
|
local function rejectWrongPlaceId(infoResponseBody)
|
||||||
if infoResponseBody.expectedPlaceIds ~= nil then
|
if infoResponseBody.expectedPlaceIds ~= nil then
|
||||||
local foundId = false
|
local foundId = table.find(infoResponseBody.expectedPlaceIds, game.PlaceId)
|
||||||
|
|
||||||
for _, id in ipairs(infoResponseBody.expectedPlaceIds) do
|
|
||||||
if id == game.PlaceId then
|
|
||||||
foundId = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not foundId then
|
if not foundId then
|
||||||
local idList = {}
|
local idList = {}
|
||||||
@@ -62,10 +55,30 @@ local function rejectWrongPlaceId(infoResponseBody)
|
|||||||
|
|
||||||
local message = (
|
local message = (
|
||||||
"Found a Rojo server, but its project is set to only be used with a specific list of places."
|
"Found a Rojo server, but its project is set to only be used with a specific list of places."
|
||||||
.. "\nYour place ID is %s, but needs to be one of these:"
|
.. "\nYour place ID is %u, but needs to be one of these:"
|
||||||
.. "\n%s"
|
.. "\n%s"
|
||||||
.. "\n\nTo change this list, edit 'servePlaceIds' in your .project.json file."
|
.. "\n\nTo change this list, edit 'servePlaceIds' in your .project.json file."
|
||||||
):format(tostring(game.PlaceId), table.concat(idList, "\n"))
|
):format(game.PlaceId, table.concat(idList, "\n"))
|
||||||
|
|
||||||
|
return Promise.reject(message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if infoResponseBody.unexpectedPlaceIds ~= nil then
|
||||||
|
local foundId = table.find(infoResponseBody.unexpectedPlaceIds, game.PlaceId)
|
||||||
|
|
||||||
|
if foundId then
|
||||||
|
local idList = {}
|
||||||
|
for _, id in ipairs(infoResponseBody.unexpectedPlaceIds) do
|
||||||
|
table.insert(idList, "- " .. tostring(id))
|
||||||
|
end
|
||||||
|
|
||||||
|
local message = (
|
||||||
|
"Found a Rojo server, but its project is set to not be used with a specific list of places."
|
||||||
|
.. "\nYour place ID is %u, but needs to not be one of these:"
|
||||||
|
.. "\n%s"
|
||||||
|
.. "\n\nTo change this list, edit 'blockedPlaceIds' in your .project.json file."
|
||||||
|
):format(game.PlaceId, table.concat(idList, "\n"))
|
||||||
|
|
||||||
return Promise.reject(message)
|
return Promise.reject(message)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ end
|
|||||||
|
|
||||||
function Checkbox:render()
|
function Checkbox:render()
|
||||||
return Theme.with(function(theme)
|
return Theme.with(function(theme)
|
||||||
theme = theme.Checkbox
|
local checkboxTheme = theme.Checkbox
|
||||||
|
|
||||||
local activeTransparency = Roact.joinBindings({
|
local activeTransparency = Roact.joinBindings({
|
||||||
self.binding:map(function(value)
|
self.binding:map(function(value)
|
||||||
@@ -57,20 +57,21 @@ function Checkbox:render()
|
|||||||
end,
|
end,
|
||||||
}, {
|
}, {
|
||||||
StateTip = e(Tooltip.Trigger, {
|
StateTip = e(Tooltip.Trigger, {
|
||||||
text = (if self.props.locked then "[LOCKED] " else "")
|
text = (if self.props.locked
|
||||||
.. (if self.props.active then "Enabled" else "Disabled"),
|
then (self.props.lockedTooltip or "(Cannot be changed right now)") .. "\n"
|
||||||
|
else "") .. (if self.props.active then "Enabled" else "Disabled"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Active = e(SlicedImage, {
|
Active = e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBackground,
|
slice = Assets.Slices.RoundedBackground,
|
||||||
color = theme.Active.BackgroundColor,
|
color = checkboxTheme.Active.BackgroundColor,
|
||||||
transparency = activeTransparency,
|
transparency = activeTransparency,
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
zIndex = 2,
|
zIndex = 2,
|
||||||
}, {
|
}, {
|
||||||
Icon = e("ImageLabel", {
|
Icon = e("ImageLabel", {
|
||||||
Image = if self.props.locked then Assets.Images.Checkbox.Locked else Assets.Images.Checkbox.Active,
|
Image = if self.props.locked then Assets.Images.Checkbox.Locked else Assets.Images.Checkbox.Active,
|
||||||
ImageColor3 = theme.Active.IconColor,
|
ImageColor3 = checkboxTheme.Active.IconColor,
|
||||||
ImageTransparency = activeTransparency,
|
ImageTransparency = activeTransparency,
|
||||||
|
|
||||||
Size = UDim2.new(0, 16, 0, 16),
|
Size = UDim2.new(0, 16, 0, 16),
|
||||||
@@ -83,7 +84,7 @@ function Checkbox:render()
|
|||||||
|
|
||||||
Inactive = e(SlicedImage, {
|
Inactive = e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBorder,
|
slice = Assets.Slices.RoundedBorder,
|
||||||
color = theme.Inactive.BorderColor,
|
color = checkboxTheme.Inactive.BorderColor,
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
}, {
|
}, {
|
||||||
@@ -91,7 +92,7 @@ function Checkbox:render()
|
|||||||
Image = if self.props.locked
|
Image = if self.props.locked
|
||||||
then Assets.Images.Checkbox.Locked
|
then Assets.Images.Checkbox.Locked
|
||||||
else Assets.Images.Checkbox.Inactive,
|
else Assets.Images.Checkbox.Inactive,
|
||||||
ImageColor3 = theme.Inactive.IconColor,
|
ImageColor3 = checkboxTheme.Inactive.IconColor,
|
||||||
ImageTransparency = self.props.transparency,
|
ImageTransparency = self.props.transparency,
|
||||||
|
|
||||||
Size = UDim2.new(0, 16, 0, 16),
|
Size = UDim2.new(0, 16, 0, 16),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
|
local Plugin = Rojo.Plugin
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
|
|
||||||
local Roact = require(Packages.Roact)
|
local Roact = require(Packages.Roact)
|
||||||
@@ -7,6 +8,8 @@ Highlighter.matchStudioSettings()
|
|||||||
|
|
||||||
local e = Roact.createElement
|
local e = Roact.createElement
|
||||||
|
|
||||||
|
local Theme = require(Plugin.App.Theme)
|
||||||
|
|
||||||
local CodeLabel = Roact.PureComponent:extend("CodeLabel")
|
local CodeLabel = Roact.PureComponent:extend("CodeLabel")
|
||||||
|
|
||||||
function CodeLabel:init()
|
function CodeLabel:init()
|
||||||
@@ -40,13 +43,14 @@ function CodeLabel:updateHighlights()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function CodeLabel:render()
|
function CodeLabel:render()
|
||||||
|
return Theme.with(function(theme)
|
||||||
return e("TextLabel", {
|
return e("TextLabel", {
|
||||||
Size = self.props.size,
|
Size = self.props.size,
|
||||||
Position = self.props.position,
|
Position = self.props.position,
|
||||||
Text = self.props.text,
|
Text = self.props.text,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.RobotoMono,
|
FontFace = theme.Font.Code,
|
||||||
TextSize = 16,
|
TextSize = theme.TextSize.Code,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextYAlignment = Enum.TextYAlignment.Top,
|
TextYAlignment = Enum.TextYAlignment.Top,
|
||||||
TextColor3 = Color3.fromRGB(255, 255, 255),
|
TextColor3 = Color3.fromRGB(255, 255, 255),
|
||||||
@@ -56,6 +60,7 @@ function CodeLabel:render()
|
|||||||
[Roact.Ref] = self.highlightsRef,
|
[Roact.Ref] = self.highlightsRef,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
return CodeLabel
|
return CodeLabel
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
local Plugin = Rojo.Plugin
|
local Plugin = Rojo.Plugin
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
@@ -10,9 +8,11 @@ local Flipper = require(Packages.Flipper)
|
|||||||
local Assets = require(Plugin.Assets)
|
local Assets = require(Plugin.Assets)
|
||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
local bindingUtil = require(Plugin.App.bindingUtil)
|
local bindingUtil = require(Plugin.App.bindingUtil)
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local SlicedImage = require(script.Parent.SlicedImage)
|
local SlicedImage = require(script.Parent.SlicedImage)
|
||||||
local ScrollingFrame = require(script.Parent.ScrollingFrame)
|
local ScrollingFrame = require(script.Parent.ScrollingFrame)
|
||||||
|
local Tooltip = require(script.Parent.Tooltip)
|
||||||
|
|
||||||
local e = Roact.createElement
|
local e = Roact.createElement
|
||||||
|
|
||||||
@@ -44,29 +44,29 @@ end
|
|||||||
|
|
||||||
function Dropdown:render()
|
function Dropdown:render()
|
||||||
return Theme.with(function(theme)
|
return Theme.with(function(theme)
|
||||||
theme = theme.Dropdown
|
local dropdownTheme = theme.Dropdown
|
||||||
|
|
||||||
local optionButtons = {}
|
local optionButtons = {}
|
||||||
local width = -1
|
local width = -1
|
||||||
for i, option in self.props.options do
|
for i, option in self.props.options do
|
||||||
local text = tostring(option or "")
|
local text = tostring(option or "")
|
||||||
local textSize = TextService:GetTextSize(text, 15, Enum.Font.GothamMedium, Vector2.new(math.huge, 20))
|
local textBounds = getTextBoundsAsync(text, theme.Font.Main, theme.TextSize.Body, math.huge)
|
||||||
if textSize.X > width then
|
if textBounds.X > width then
|
||||||
width = textSize.X
|
width = textBounds.X
|
||||||
end
|
end
|
||||||
|
|
||||||
optionButtons[text] = e("TextButton", {
|
optionButtons[text] = e("TextButton", {
|
||||||
Text = text,
|
Text = text,
|
||||||
LayoutOrder = i,
|
LayoutOrder = i,
|
||||||
Size = UDim2.new(1, 0, 0, 24),
|
Size = UDim2.new(1, 0, 0, 24),
|
||||||
BackgroundColor3 = theme.BackgroundColor,
|
BackgroundColor3 = dropdownTheme.BackgroundColor,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
BackgroundTransparency = self.props.transparency,
|
BackgroundTransparency = self.props.transparency,
|
||||||
BorderSizePixel = 0,
|
BorderSizePixel = 0,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = dropdownTheme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Body,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
|
|
||||||
[Roact.Event.Activated] = function()
|
[Roact.Event.Activated] = function()
|
||||||
if self.props.locked then
|
if self.props.locked then
|
||||||
@@ -103,13 +103,13 @@ function Dropdown:render()
|
|||||||
}, {
|
}, {
|
||||||
Border = e(SlicedImage, {
|
Border = e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBorder,
|
slice = Assets.Slices.RoundedBorder,
|
||||||
color = theme.BorderColor,
|
color = dropdownTheme.BorderColor,
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
}, {
|
}, {
|
||||||
DropArrow = e("ImageLabel", {
|
DropArrow = e("ImageLabel", {
|
||||||
Image = if self.props.locked then Assets.Images.Dropdown.Locked else Assets.Images.Dropdown.Arrow,
|
Image = if self.props.locked then Assets.Images.Dropdown.Locked else Assets.Images.Dropdown.Arrow,
|
||||||
ImageColor3 = theme.IconColor,
|
ImageColor3 = dropdownTheme.IconColor,
|
||||||
ImageTransparency = self.props.transparency,
|
ImageTransparency = self.props.transparency,
|
||||||
|
|
||||||
Size = UDim2.new(0, 18, 0, 18),
|
Size = UDim2.new(0, 18, 0, 18),
|
||||||
@@ -120,15 +120,21 @@ function Dropdown:render()
|
|||||||
end),
|
end),
|
||||||
|
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
|
}, {
|
||||||
|
StateTip = if self.props.locked
|
||||||
|
then e(Tooltip.Trigger, {
|
||||||
|
text = self.props.lockedTooltip or "(Cannot be changed right now)",
|
||||||
|
})
|
||||||
|
else nil,
|
||||||
}),
|
}),
|
||||||
Active = e("TextLabel", {
|
Active = e("TextLabel", {
|
||||||
Size = UDim2.new(1, -30, 1, 0),
|
Size = UDim2.new(1, -30, 1, 0),
|
||||||
Position = UDim2.new(0, 6, 0, 0),
|
Position = UDim2.new(0, 6, 0, 0),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = self.props.active,
|
Text = self.props.active,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = dropdownTheme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
}),
|
}),
|
||||||
@@ -136,7 +142,7 @@ function Dropdown:render()
|
|||||||
Options = if self.state.open
|
Options = if self.state.open
|
||||||
then e(SlicedImage, {
|
then e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBackground,
|
slice = Assets.Slices.RoundedBackground,
|
||||||
color = theme.BackgroundColor,
|
color = dropdownTheme.BackgroundColor,
|
||||||
position = UDim2.new(1, 0, 1, 3),
|
position = UDim2.new(1, 0, 1, 3),
|
||||||
size = self.openBinding:map(function(a)
|
size = self.openBinding:map(function(a)
|
||||||
return UDim2.new(1, 0, a * math.min(3, #self.props.options), 0)
|
return UDim2.new(1, 0, a * math.min(3, #self.props.options), 0)
|
||||||
@@ -145,7 +151,7 @@ function Dropdown:render()
|
|||||||
}, {
|
}, {
|
||||||
Border = e(SlicedImage, {
|
Border = e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBorder,
|
slice = Assets.Slices.RoundedBorder,
|
||||||
color = theme.BorderColor,
|
color = dropdownTheme.BorderColor,
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ local function Header(props)
|
|||||||
|
|
||||||
Version = e("TextLabel", {
|
Version = e("TextLabel", {
|
||||||
Text = Version.display(Config.version),
|
Text = Version.display(Config.version),
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Header.VersionColor,
|
TextColor3 = theme.Header.VersionColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
|
|
||||||
Size = UDim2.new(1, 0, 0, 14),
|
Size = UDim2.new(1, 0, 0, theme.TextSize.Body),
|
||||||
|
|
||||||
LayoutOrder = 2,
|
LayoutOrder = 2,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ local function ViewDiffButton(props)
|
|||||||
Label = e("TextLabel", {
|
Label = e("TextLabel", {
|
||||||
Text = "View Diff",
|
Text = "View Diff",
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -170,8 +170,8 @@ function ChangeList:render()
|
|||||||
ColumnA = e("TextLabel", {
|
ColumnA = e("TextLabel", {
|
||||||
Text = tostring(headerRow[1]),
|
Text = tostring(headerRow[1]),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -182,8 +182,8 @@ function ChangeList:render()
|
|||||||
ColumnB = e("TextLabel", {
|
ColumnB = e("TextLabel", {
|
||||||
Text = tostring(headerRow[2]),
|
Text = tostring(headerRow[2]),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -194,8 +194,8 @@ function ChangeList:render()
|
|||||||
ColumnC = e("TextLabel", {
|
ColumnC = e("TextLabel", {
|
||||||
Text = tostring(headerRow[3]),
|
Text = tostring(headerRow[3]),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -230,8 +230,8 @@ function ChangeList:render()
|
|||||||
ColumnA = e("TextLabel", {
|
ColumnA = e("TextLabel", {
|
||||||
Text = (if isWarning then "⚠ " else "") .. tostring(values[1]),
|
Text = (if isWarning then "⚠ " else "") .. tostring(values[1]),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = if isWarning then theme.Diff.Warning else theme.TextColor,
|
TextColor3 = if isWarning then theme.Diff.Warning else theme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ local function DisplayValue(props)
|
|||||||
Label = e("TextLabel", {
|
Label = e("TextLabel", {
|
||||||
Text = string.format("%d, %d, %d", props.value.R * 255, props.value.G * 255, props.value.B * 255),
|
Text = string.format("%d, %d, %d", props.value.R * 255, props.value.G * 255, props.value.B * 255),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = props.textColor,
|
TextColor3 = props.textColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -90,8 +90,8 @@ local function DisplayValue(props)
|
|||||||
return e("TextLabel", {
|
return e("TextLabel", {
|
||||||
Text = textRepresentation,
|
Text = textRepresentation,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = props.textColor,
|
TextColor3 = props.textColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -112,8 +112,8 @@ local function DisplayValue(props)
|
|||||||
return e("TextLabel", {
|
return e("TextLabel", {
|
||||||
Text = textRepresentation,
|
Text = textRepresentation,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = props.textColor,
|
TextColor3 = props.textColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
|
|||||||
@@ -225,8 +225,8 @@ function DomLabel:render()
|
|||||||
Text = (if props.isWarning then "⚠ " else "") .. props.name,
|
Text = (if props.isWarning then "⚠ " else "") .. props.name,
|
||||||
RichText = true,
|
RichText = true,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = if props.patchType then Enum.Font.GothamBold else Enum.Font.GothamMedium,
|
FontFace = if props.patchType then theme.Font.Bold else theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = color,
|
TextColor3 = color,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -251,11 +251,11 @@ function DomLabel:render()
|
|||||||
then e("TextLabel", {
|
then e("TextLabel", {
|
||||||
Text = props.changeInfo.edits .. if props.changeInfo.failed then "," else "",
|
Text = props.changeInfo.edits .. if props.changeInfo.failed then "," else "",
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.SubTextColor,
|
TextColor3 = theme.SubTextColor,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
Size = UDim2.new(0, 0, 0, 16),
|
Size = UDim2.new(0, 0, 0, theme.TextSize.Body),
|
||||||
AutomaticSize = Enum.AutomaticSize.X,
|
AutomaticSize = Enum.AutomaticSize.X,
|
||||||
LayoutOrder = 2,
|
LayoutOrder = 2,
|
||||||
})
|
})
|
||||||
@@ -264,11 +264,11 @@ function DomLabel:render()
|
|||||||
then e("TextLabel", {
|
then e("TextLabel", {
|
||||||
Text = props.changeInfo.failed,
|
Text = props.changeInfo.failed,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Diff.Warning,
|
TextColor3 = theme.Diff.Warning,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
Size = UDim2.new(0, 0, 0, 16),
|
Size = UDim2.new(0, 0, 0, theme.TextSize.Body),
|
||||||
AutomaticSize = Enum.AutomaticSize.X,
|
AutomaticSize = Enum.AutomaticSize.X,
|
||||||
LayoutOrder = 6,
|
LayoutOrder = 6,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ function PatchVisualizer:render()
|
|||||||
CleanMerge = e("TextLabel", {
|
CleanMerge = e("TextLabel", {
|
||||||
Visible = #scrollElements == 0,
|
Visible = #scrollElements == 0,
|
||||||
Text = "No changes to sync, project is up to date.",
|
Text = "No changes to sync, project is up to date.",
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Medium,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextWrapped = true,
|
TextWrapped = true,
|
||||||
Size = UDim2.new(1, 0, 1, 0),
|
Size = UDim2.new(1, 0, 1, 0),
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
local Plugin = Rojo.Plugin
|
local Plugin = Rojo.Plugin
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
@@ -11,6 +9,7 @@ local StringDiff = require(script:FindFirstChild("StringDiff"))
|
|||||||
|
|
||||||
local Timer = require(Plugin.Timer)
|
local Timer = require(Plugin.Timer)
|
||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local CodeLabel = require(Plugin.App.Components.CodeLabel)
|
local CodeLabel = require(Plugin.App.Components.CodeLabel)
|
||||||
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
||||||
@@ -32,7 +31,6 @@ function StringDiffVisualizer:init()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
self:calculateContentSize()
|
|
||||||
self:updateScriptBackground()
|
self:updateScriptBackground()
|
||||||
|
|
||||||
self:setState({
|
self:setState({
|
||||||
@@ -54,7 +52,6 @@ end
|
|||||||
|
|
||||||
function StringDiffVisualizer:didUpdate(previousProps)
|
function StringDiffVisualizer:didUpdate(previousProps)
|
||||||
if previousProps.oldString ~= self.props.oldString or previousProps.newString ~= self.props.newString then
|
if previousProps.oldString ~= self.props.oldString or previousProps.newString ~= self.props.newString then
|
||||||
self:calculateContentSize()
|
|
||||||
local add, remove = self:calculateDiffLines()
|
local add, remove = self:calculateDiffLines()
|
||||||
self:setState({
|
self:setState({
|
||||||
add = add,
|
add = add,
|
||||||
@@ -63,11 +60,11 @@ function StringDiffVisualizer:didUpdate(previousProps)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function StringDiffVisualizer:calculateContentSize()
|
function StringDiffVisualizer:calculateContentSize(theme)
|
||||||
local oldString, newString = self.props.oldString, self.props.newString
|
local oldString, newString = self.props.oldString, self.props.newString
|
||||||
|
|
||||||
local oldStringBounds = TextService:GetTextSize(oldString, 16, Enum.Font.RobotoMono, Vector2.new(99999, 99999))
|
local oldStringBounds = getTextBoundsAsync(oldString, theme.Font.Code, theme.TextSize.Code, math.huge)
|
||||||
local newStringBounds = TextService:GetTextSize(newString, 16, Enum.Font.RobotoMono, Vector2.new(99999, 99999))
|
local newStringBounds = getTextBoundsAsync(newString, theme.Font.Code, theme.TextSize.Code, math.huge)
|
||||||
|
|
||||||
self.setContentSize(
|
self.setContentSize(
|
||||||
Vector2.new(math.max(oldStringBounds.X, newStringBounds.X), math.max(oldStringBounds.Y, newStringBounds.Y))
|
Vector2.new(math.max(oldStringBounds.X, newStringBounds.X), math.max(oldStringBounds.Y, newStringBounds.Y))
|
||||||
@@ -143,6 +140,8 @@ function StringDiffVisualizer:render()
|
|||||||
local oldString, newString = self.props.oldString, self.props.newString
|
local oldString, newString = self.props.oldString, self.props.newString
|
||||||
|
|
||||||
return Theme.with(function(theme)
|
return Theme.with(function(theme)
|
||||||
|
self:calculateContentSize(theme)
|
||||||
|
|
||||||
return e(BorderedContainer, {
|
return e(BorderedContainer, {
|
||||||
size = self.props.size,
|
size = self.props.size,
|
||||||
position = self.props.position,
|
position = self.props.position,
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ function Array:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = "Old",
|
Text = "Old",
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
}),
|
}),
|
||||||
@@ -163,8 +163,8 @@ function Array:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = "New",
|
Text = "New",
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ function Dictionary:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = key,
|
Text = key,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
}),
|
}),
|
||||||
@@ -157,8 +157,8 @@ function Dictionary:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = "Key",
|
Text = "Key",
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
}),
|
}),
|
||||||
@@ -168,8 +168,8 @@ function Dictionary:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = "Old",
|
Text = "Old",
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
}),
|
}),
|
||||||
@@ -179,8 +179,8 @@ function Dictionary:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = "New",
|
Text = "New",
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
TextColor3 = theme.Settings.Setting.DescriptionColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ local Packages = Rojo.Packages
|
|||||||
|
|
||||||
local Roact = require(Packages.Roact)
|
local Roact = require(Packages.Roact)
|
||||||
|
|
||||||
|
local Theme = require(Plugin.App.Theme)
|
||||||
local Assets = require(Plugin.Assets)
|
local Assets = require(Plugin.Assets)
|
||||||
|
|
||||||
local SlicedImage = require(Plugin.App.Components.SlicedImage)
|
local SlicedImage = require(Plugin.App.Components.SlicedImage)
|
||||||
@@ -11,6 +12,7 @@ local SlicedImage = require(Plugin.App.Components.SlicedImage)
|
|||||||
local e = Roact.createElement
|
local e = Roact.createElement
|
||||||
|
|
||||||
return function(props)
|
return function(props)
|
||||||
|
return Theme.with(function(theme)
|
||||||
return e(SlicedImage, {
|
return e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBackground,
|
slice = Assets.Slices.RoundedBackground,
|
||||||
color = props.color,
|
color = props.color,
|
||||||
@@ -20,7 +22,7 @@ return function(props)
|
|||||||
layoutOrder = props.layoutOrder,
|
layoutOrder = props.layoutOrder,
|
||||||
position = props.position,
|
position = props.position,
|
||||||
anchorPoint = props.anchorPoint,
|
anchorPoint = props.anchorPoint,
|
||||||
size = UDim2.new(0, 0, 0, 16),
|
size = UDim2.new(0, 0, 0, theme.TextSize.Medium),
|
||||||
automaticSize = Enum.AutomaticSize.X,
|
automaticSize = Enum.AutomaticSize.X,
|
||||||
}, {
|
}, {
|
||||||
Padding = e("UIPadding", {
|
Padding = e("UIPadding", {
|
||||||
@@ -42,8 +44,8 @@ return function(props)
|
|||||||
else nil,
|
else nil,
|
||||||
Text = e("TextLabel", {
|
Text = e("TextLabel", {
|
||||||
Text = props.text,
|
Text = props.text,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 12,
|
TextSize = theme.TextSize.Small,
|
||||||
TextColor3 = props.color,
|
TextColor3 = props.color,
|
||||||
TextXAlignment = Enum.TextXAlignment.Center,
|
TextXAlignment = Enum.TextXAlignment.Center,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -53,4 +55,5 @@ return function(props)
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
local Plugin = Rojo.Plugin
|
local Plugin = Rojo.Plugin
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
@@ -10,6 +8,7 @@ local Flipper = require(Packages.Flipper)
|
|||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
local Assets = require(Plugin.Assets)
|
local Assets = require(Plugin.Assets)
|
||||||
local bindingUtil = require(Plugin.App.bindingUtil)
|
local bindingUtil = require(Plugin.App.bindingUtil)
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local SlicedImage = require(script.Parent.SlicedImage)
|
local SlicedImage = require(script.Parent.SlicedImage)
|
||||||
local TouchRipple = require(script.Parent.TouchRipple)
|
local TouchRipple = require(script.Parent.TouchRipple)
|
||||||
@@ -41,18 +40,17 @@ end
|
|||||||
|
|
||||||
function TextButton:render()
|
function TextButton:render()
|
||||||
return Theme.with(function(theme)
|
return Theme.with(function(theme)
|
||||||
local textSize =
|
local textBounds = getTextBoundsAsync(self.props.text, theme.Font.Main, theme.TextSize.Large, math.huge)
|
||||||
TextService:GetTextSize(self.props.text, 18, Enum.Font.GothamMedium, Vector2.new(math.huge, math.huge))
|
|
||||||
|
|
||||||
local style = self.props.style
|
local style = self.props.style
|
||||||
|
|
||||||
theme = theme.Button[style]
|
local buttonTheme = theme.Button[style]
|
||||||
|
|
||||||
local bindingHover = bindingUtil.deriveProperty(self.binding, "hover")
|
local bindingHover = bindingUtil.deriveProperty(self.binding, "hover")
|
||||||
local bindingEnabled = bindingUtil.deriveProperty(self.binding, "enabled")
|
local bindingEnabled = bindingUtil.deriveProperty(self.binding, "enabled")
|
||||||
|
|
||||||
return e("ImageButton", {
|
return e("ImageButton", {
|
||||||
Size = UDim2.new(0, 15 + textSize.X + 15, 0, 34),
|
Size = UDim2.new(0, (theme.TextSize.Body * 2) + textBounds.X, 0, 34),
|
||||||
Position = self.props.position,
|
Position = self.props.position,
|
||||||
AnchorPoint = self.props.anchorPoint,
|
AnchorPoint = self.props.anchorPoint,
|
||||||
|
|
||||||
@@ -74,18 +72,22 @@ function TextButton:render()
|
|||||||
end,
|
end,
|
||||||
}, {
|
}, {
|
||||||
TouchRipple = e(TouchRipple, {
|
TouchRipple = e(TouchRipple, {
|
||||||
color = theme.ActionFillColor,
|
color = buttonTheme.ActionFillColor,
|
||||||
transparency = self.props.transparency:map(function(value)
|
transparency = self.props.transparency:map(function(value)
|
||||||
return bindingUtil.blendAlpha({ theme.ActionFillTransparency, value })
|
return bindingUtil.blendAlpha({ buttonTheme.ActionFillTransparency, value })
|
||||||
end),
|
end),
|
||||||
zIndex = 2,
|
zIndex = 2,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Text = e("TextLabel", {
|
Text = e("TextLabel", {
|
||||||
Text = self.props.text,
|
Text = self.props.text,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 18,
|
TextSize = theme.TextSize.Large,
|
||||||
TextColor3 = bindingUtil.mapLerp(bindingEnabled, theme.Enabled.TextColor, theme.Disabled.TextColor),
|
TextColor3 = bindingUtil.mapLerp(
|
||||||
|
bindingEnabled,
|
||||||
|
buttonTheme.Enabled.TextColor,
|
||||||
|
buttonTheme.Disabled.TextColor
|
||||||
|
),
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
|
|
||||||
Size = UDim2.new(1, 0, 1, 0),
|
Size = UDim2.new(1, 0, 1, 0),
|
||||||
@@ -95,7 +97,11 @@ function TextButton:render()
|
|||||||
|
|
||||||
Border = style == "Bordered" and e(SlicedImage, {
|
Border = style == "Bordered" and e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBorder,
|
slice = Assets.Slices.RoundedBorder,
|
||||||
color = bindingUtil.mapLerp(bindingEnabled, theme.Enabled.BorderColor, theme.Disabled.BorderColor),
|
color = bindingUtil.mapLerp(
|
||||||
|
bindingEnabled,
|
||||||
|
buttonTheme.Enabled.BorderColor,
|
||||||
|
buttonTheme.Disabled.BorderColor
|
||||||
|
),
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
|
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
@@ -105,14 +111,18 @@ function TextButton:render()
|
|||||||
|
|
||||||
HoverOverlay = e(SlicedImage, {
|
HoverOverlay = e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBackground,
|
slice = Assets.Slices.RoundedBackground,
|
||||||
color = theme.ActionFillColor,
|
color = buttonTheme.ActionFillColor,
|
||||||
transparency = Roact.joinBindings({
|
transparency = Roact.joinBindings({
|
||||||
hover = bindingHover:map(function(value)
|
hover = bindingHover:map(function(value)
|
||||||
return 1 - value
|
return 1 - value
|
||||||
end),
|
end),
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
}):map(function(values)
|
}):map(function(values)
|
||||||
return bindingUtil.blendAlpha({ theme.ActionFillTransparency, values.hover, values.transparency })
|
return bindingUtil.blendAlpha({
|
||||||
|
buttonTheme.ActionFillTransparency,
|
||||||
|
values.hover,
|
||||||
|
values.transparency,
|
||||||
|
})
|
||||||
end),
|
end),
|
||||||
|
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
@@ -124,8 +134,8 @@ function TextButton:render()
|
|||||||
slice = Assets.Slices.RoundedBackground,
|
slice = Assets.Slices.RoundedBackground,
|
||||||
color = bindingUtil.mapLerp(
|
color = bindingUtil.mapLerp(
|
||||||
bindingEnabled,
|
bindingEnabled,
|
||||||
theme.Enabled.BackgroundColor,
|
buttonTheme.Enabled.BackgroundColor,
|
||||||
theme.Disabled.BackgroundColor
|
buttonTheme.Disabled.BackgroundColor
|
||||||
),
|
),
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
|
|
||||||
|
|||||||
@@ -38,14 +38,18 @@ end
|
|||||||
|
|
||||||
function TextInput:render()
|
function TextInput:render()
|
||||||
return Theme.with(function(theme)
|
return Theme.with(function(theme)
|
||||||
theme = theme.TextInput
|
local textInputTheme = theme.TextInput
|
||||||
|
|
||||||
local bindingHover = bindingUtil.deriveProperty(self.binding, "hover")
|
local bindingHover = bindingUtil.deriveProperty(self.binding, "hover")
|
||||||
local bindingEnabled = bindingUtil.deriveProperty(self.binding, "enabled")
|
local bindingEnabled = bindingUtil.deriveProperty(self.binding, "enabled")
|
||||||
|
|
||||||
return e(SlicedImage, {
|
return e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBorder,
|
slice = Assets.Slices.RoundedBorder,
|
||||||
color = bindingUtil.mapLerp(bindingEnabled, theme.Enabled.BorderColor, theme.Disabled.BorderColor),
|
color = bindingUtil.mapLerp(
|
||||||
|
bindingEnabled,
|
||||||
|
textInputTheme.Enabled.BorderColor,
|
||||||
|
textInputTheme.Disabled.BorderColor
|
||||||
|
),
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
|
|
||||||
size = self.props.size or UDim2.new(1, 0, 1, 0),
|
size = self.props.size or UDim2.new(1, 0, 1, 0),
|
||||||
@@ -55,14 +59,18 @@ function TextInput:render()
|
|||||||
}, {
|
}, {
|
||||||
HoverOverlay = e(SlicedImage, {
|
HoverOverlay = e(SlicedImage, {
|
||||||
slice = Assets.Slices.RoundedBackground,
|
slice = Assets.Slices.RoundedBackground,
|
||||||
color = theme.ActionFillColor,
|
color = textInputTheme.ActionFillColor,
|
||||||
transparency = Roact.joinBindings({
|
transparency = Roact.joinBindings({
|
||||||
hover = bindingHover:map(function(value)
|
hover = bindingHover:map(function(value)
|
||||||
return 1 - value
|
return 1 - value
|
||||||
end),
|
end),
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
}):map(function(values)
|
}):map(function(values)
|
||||||
return bindingUtil.blendAlpha({ theme.ActionFillTransparency, values.hover, values.transparency })
|
return bindingUtil.blendAlpha({
|
||||||
|
textInputTheme.ActionFillTransparency,
|
||||||
|
values.hover,
|
||||||
|
values.transparency,
|
||||||
|
})
|
||||||
end),
|
end),
|
||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
zIndex = -1,
|
zIndex = -1,
|
||||||
@@ -72,14 +80,18 @@ function TextInput:render()
|
|||||||
Size = UDim2.fromScale(1, 1),
|
Size = UDim2.fromScale(1, 1),
|
||||||
Text = self.props.text,
|
Text = self.props.text,
|
||||||
PlaceholderText = self.props.placeholder,
|
PlaceholderText = self.props.placeholder,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextColor3 = bindingUtil.mapLerp(bindingEnabled, theme.Disabled.TextColor, theme.Enabled.TextColor),
|
TextColor3 = bindingUtil.mapLerp(
|
||||||
|
bindingEnabled,
|
||||||
|
textInputTheme.Disabled.TextColor,
|
||||||
|
textInputTheme.Enabled.TextColor
|
||||||
|
),
|
||||||
PlaceholderColor3 = bindingUtil.mapLerp(
|
PlaceholderColor3 = bindingUtil.mapLerp(
|
||||||
bindingEnabled,
|
bindingEnabled,
|
||||||
theme.Disabled.PlaceholderColor,
|
textInputTheme.Disabled.PlaceholderColor,
|
||||||
theme.Enabled.PlaceholderColor
|
textInputTheme.Enabled.PlaceholderColor
|
||||||
),
|
),
|
||||||
TextSize = 18,
|
TextSize = theme.TextSize.Large,
|
||||||
TextEditable = self.props.enabled,
|
TextEditable = self.props.enabled,
|
||||||
ClearTextOnFocus = self.props.clearTextOnFocus,
|
ClearTextOnFocus = self.props.clearTextOnFocus,
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
local HttpService = game:GetService("HttpService")
|
local HttpService = game:GetService("HttpService")
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
@@ -8,6 +7,8 @@ local Packages = Rojo.Packages
|
|||||||
local Roact = require(Packages.Roact)
|
local Roact = require(Packages.Roact)
|
||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
|
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
||||||
|
|
||||||
local e = Roact.createElement
|
local e = Roact.createElement
|
||||||
@@ -21,12 +22,10 @@ local Y_OVERLAP = 10 -- Let the triangle tail piece overlap the target a bit to
|
|||||||
local TooltipContext = Roact.createContext({})
|
local TooltipContext = Roact.createContext({})
|
||||||
|
|
||||||
local function Popup(props)
|
local function Popup(props)
|
||||||
local textSize = TextService:GetTextSize(
|
return Theme.with(function(theme)
|
||||||
props.Text,
|
local textXSpace = math.min(props.parentSize.X, 250) - TEXT_PADDING.X
|
||||||
16,
|
local textBounds = getTextBoundsAsync(props.Text, theme.Font.Main, theme.TextSize.Medium, textXSpace)
|
||||||
Enum.Font.GothamMedium,
|
local contentSize = textBounds + TEXT_PADDING + (Vector2.one * 2)
|
||||||
Vector2.new(math.min(props.parentSize.X, 160), math.huge)
|
|
||||||
) + TEXT_PADDING + (Vector2.one * 2)
|
|
||||||
|
|
||||||
local trigger = props.Trigger:getValue()
|
local trigger = props.Trigger:getValue()
|
||||||
|
|
||||||
@@ -35,36 +34,36 @@ local function Popup(props)
|
|||||||
local spaceAbove = trigger.AbsolutePosition.Y + Y_OVERLAP - TAIL_SIZE
|
local spaceAbove = trigger.AbsolutePosition.Y + Y_OVERLAP - TAIL_SIZE
|
||||||
|
|
||||||
-- If there's not enough space below, and there's more space above, then show the tooltip above the trigger
|
-- If there's not enough space below, and there's more space above, then show the tooltip above the trigger
|
||||||
local displayAbove = spaceBelow < textSize.Y and spaceAbove > spaceBelow
|
local displayAbove = spaceBelow < contentSize.Y and spaceAbove > spaceBelow
|
||||||
|
|
||||||
local X = math.clamp(props.Position.X - X_OFFSET, 0, props.parentSize.X - textSize.X)
|
local X = math.clamp(props.Position.X - X_OFFSET, 0, math.max(props.parentSize.X - contentSize.X, 1))
|
||||||
local Y = 0
|
local Y = 0
|
||||||
|
|
||||||
if displayAbove then
|
if displayAbove then
|
||||||
Y = math.max(trigger.AbsolutePosition.Y - TAIL_SIZE - textSize.Y + Y_OVERLAP, 0)
|
Y = math.max(trigger.AbsolutePosition.Y - TAIL_SIZE - contentSize.Y + Y_OVERLAP, 0)
|
||||||
else
|
else
|
||||||
Y = math.min(
|
Y = math.min(
|
||||||
trigger.AbsolutePosition.Y + trigger.AbsoluteSize.Y + TAIL_SIZE - Y_OVERLAP,
|
trigger.AbsolutePosition.Y + trigger.AbsoluteSize.Y + TAIL_SIZE - Y_OVERLAP,
|
||||||
props.parentSize.Y - textSize.Y
|
props.parentSize.Y - contentSize.Y
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
return Theme.with(function(theme)
|
|
||||||
return e(BorderedContainer, {
|
return e(BorderedContainer, {
|
||||||
position = UDim2.fromOffset(X, Y),
|
position = UDim2.fromOffset(X, Y),
|
||||||
size = UDim2.fromOffset(textSize.X, textSize.Y),
|
size = UDim2.fromOffset(contentSize.X, contentSize.Y),
|
||||||
transparency = props.transparency,
|
transparency = props.transparency,
|
||||||
}, {
|
}, {
|
||||||
Label = e("TextLabel", {
|
Label = e("TextLabel", {
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Position = UDim2.fromScale(0.5, 0.5),
|
Position = UDim2.fromScale(0.5, 0.5),
|
||||||
Size = UDim2.new(1, -TEXT_PADDING.X, 1, -TEXT_PADDING.Y),
|
|
||||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||||
|
Size = UDim2.fromOffset(textBounds.X, textBounds.Y),
|
||||||
Text = props.Text,
|
Text = props.Text,
|
||||||
TextSize = 16,
|
TextSize = theme.TextSize.Medium,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextWrapped = true,
|
TextWrapped = true,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
|
TextYAlignment = Enum.TextYAlignment.Center,
|
||||||
TextColor3 = theme.Button.Bordered.Enabled.TextColor,
|
TextColor3 = theme.Button.Bordered.Enabled.TextColor,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
}),
|
}),
|
||||||
@@ -72,8 +71,8 @@ local function Popup(props)
|
|||||||
Tail = e("ImageLabel", {
|
Tail = e("ImageLabel", {
|
||||||
ZIndex = 100,
|
ZIndex = 100,
|
||||||
Position = if displayAbove
|
Position = if displayAbove
|
||||||
then UDim2.new(0, math.clamp(props.Position.X - X, 6, textSize.X - 6), 1, -1)
|
then UDim2.new(0, math.clamp(props.Position.X - X, 6, contentSize.X - 6), 1, -1)
|
||||||
else UDim2.new(0, math.clamp(props.Position.X - X, 6, textSize.X - 6), 0, -TAIL_SIZE + 1),
|
else UDim2.new(0, math.clamp(props.Position.X - X, 6, contentSize.X - 6), 0, -TAIL_SIZE + 1),
|
||||||
Size = UDim2.fromOffset(TAIL_SIZE, TAIL_SIZE),
|
Size = UDim2.fromOffset(TAIL_SIZE, TAIL_SIZE),
|
||||||
AnchorPoint = Vector2.new(0.5, 0),
|
AnchorPoint = Vector2.new(0.5, 0),
|
||||||
Rotation = if displayAbove then 180 else 0,
|
Rotation = if displayAbove then 180 else 0,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
local StudioService = game:GetService("StudioService")
|
local StudioService = game:GetService("StudioService")
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
@@ -9,10 +8,10 @@ local Roact = require(Packages.Roact)
|
|||||||
local Flipper = require(Packages.Flipper)
|
local Flipper = require(Packages.Flipper)
|
||||||
local Log = require(Packages.Log)
|
local Log = require(Packages.Log)
|
||||||
|
|
||||||
local bindingUtil = require(script.Parent.bindingUtil)
|
|
||||||
|
|
||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
local Assets = require(Plugin.Assets)
|
local Assets = require(Plugin.Assets)
|
||||||
|
local bindingUtil = require(Plugin.App.bindingUtil)
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
||||||
local TextButton = require(Plugin.App.Components.TextButton)
|
local TextButton = require(Plugin.App.Components.TextButton)
|
||||||
@@ -86,8 +85,7 @@ function Notification:render()
|
|||||||
return 1 - value
|
return 1 - value
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local textBounds = TextService:GetTextSize(self.props.text, 15, Enum.Font.GothamMedium, Vector2.new(350, 700))
|
return Theme.with(function(theme)
|
||||||
|
|
||||||
local actionButtons = {}
|
local actionButtons = {}
|
||||||
local buttonsX = 0
|
local buttonsX = 0
|
||||||
if self.props.actions then
|
if self.props.actions then
|
||||||
@@ -106,12 +104,7 @@ function Notification:render()
|
|||||||
transparency = transparency,
|
transparency = transparency,
|
||||||
})
|
})
|
||||||
|
|
||||||
buttonsX += TextService:GetTextSize(
|
buttonsX += getTextBoundsAsync(action.text, theme.Font.Main, theme.TextSize.Large, math.huge).X + (theme.TextSize.Body * 2)
|
||||||
action.text,
|
|
||||||
18,
|
|
||||||
Enum.Font.GothamMedium,
|
|
||||||
Vector2.new(math.huge, math.huge)
|
|
||||||
).X + 30
|
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
@@ -120,7 +113,9 @@ function Notification:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local paddingY, logoSize = 20, 32
|
local paddingY, logoSize = 20, 32
|
||||||
local actionsY = if self.props.actions then 35 else 0
|
local actionsY = if self.props.actions then 37 else 0
|
||||||
|
local textXSpace = math.max(250, buttonsX) + 35
|
||||||
|
local textBounds = getTextBoundsAsync(self.props.text, theme.Font.Main, theme.TextSize.Body, textXSpace)
|
||||||
local contentX = math.max(textBounds.X, buttonsX)
|
local contentX = math.max(textBounds.X, buttonsX)
|
||||||
|
|
||||||
local size = self.binding:map(function(value)
|
local size = self.binding:map(function(value)
|
||||||
@@ -130,7 +125,6 @@ function Notification:render()
|
|||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
return Theme.with(function(theme)
|
|
||||||
return e("TextButton", {
|
return e("TextButton", {
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Size = size,
|
Size = size,
|
||||||
@@ -147,8 +141,7 @@ function Notification:render()
|
|||||||
size = UDim2.new(1, 0, 1, 0),
|
size = UDim2.new(1, 0, 1, 0),
|
||||||
}, {
|
}, {
|
||||||
Contents = e("Frame", {
|
Contents = e("Frame", {
|
||||||
Size = UDim2.new(0, 35 + contentX, 1, -paddingY),
|
Size = UDim2.new(1, 0, 1, 0),
|
||||||
Position = UDim2.new(0, 0, 0, paddingY / 2),
|
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}, {
|
}, {
|
||||||
Logo = e("ImageLabel", {
|
Logo = e("ImageLabel", {
|
||||||
@@ -161,14 +154,15 @@ function Notification:render()
|
|||||||
}),
|
}),
|
||||||
Info = e("TextLabel", {
|
Info = e("TextLabel", {
|
||||||
Text = self.props.text,
|
Text = self.props.text,
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Notification.InfoColor,
|
TextColor3 = theme.Notification.InfoColor,
|
||||||
TextTransparency = transparency,
|
TextTransparency = transparency,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
|
TextYAlignment = Enum.TextYAlignment.Center,
|
||||||
TextWrapped = true,
|
TextWrapped = true,
|
||||||
|
|
||||||
Size = UDim2.new(0, textBounds.X, 0, textBounds.Y),
|
Size = UDim2.new(0, textBounds.X, 1, -actionsY),
|
||||||
Position = UDim2.fromOffset(35, 0),
|
Position = UDim2.fromOffset(35, 0),
|
||||||
|
|
||||||
LayoutOrder = 1,
|
LayoutOrder = 1,
|
||||||
@@ -176,7 +170,7 @@ function Notification:render()
|
|||||||
}),
|
}),
|
||||||
Actions = if self.props.actions
|
Actions = if self.props.actions
|
||||||
then e("Frame", {
|
then e("Frame", {
|
||||||
Size = UDim2.new(1, -40, 0, 35),
|
Size = UDim2.new(1, -40, 0, actionsY),
|
||||||
Position = UDim2.new(1, 0, 1, 0),
|
Position = UDim2.new(1, 0, 1, 0),
|
||||||
AnchorPoint = Vector2.new(1, 1),
|
AnchorPoint = Vector2.new(1, 1),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
@@ -196,6 +190,8 @@ function Notification:render()
|
|||||||
Padding = e("UIPadding", {
|
Padding = e("UIPadding", {
|
||||||
PaddingLeft = UDim.new(0, 17),
|
PaddingLeft = UDim.new(0, 17),
|
||||||
PaddingRight = UDim.new(0, 15),
|
PaddingRight = UDim.new(0, 15),
|
||||||
|
PaddingTop = UDim.new(0, paddingY / 2),
|
||||||
|
PaddingBottom = UDim.new(0, paddingY / 2),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -64,13 +64,13 @@ function ConfirmingPage:render()
|
|||||||
"Sync changes for project '%s':",
|
"Sync changes for project '%s':",
|
||||||
self.props.confirmData.serverInfo.projectName or "UNKNOWN"
|
self.props.confirmData.serverInfo.projectName or "UNKNOWN"
|
||||||
),
|
),
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
LineHeight = 1.2,
|
LineHeight = 1.2,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
Size = UDim2.new(1, 0, 0, 20),
|
Size = UDim2.new(1, 0, 0, theme.TextSize.Large + 2),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@@ -61,12 +61,12 @@ function ChangesViewer:render()
|
|||||||
|
|
||||||
Title = e("TextLabel", {
|
Title = e("TextLabel", {
|
||||||
Text = "Sync",
|
Text = "Sync",
|
||||||
Font = Enum.Font.GothamMedium,
|
FontFace = theme.Font.Main,
|
||||||
TextSize = 17,
|
TextSize = theme.TextSize.Large,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
Size = UDim2.new(1, -40, 0, 20),
|
Size = UDim2.new(1, -40, 0, theme.TextSize.Large + 2),
|
||||||
Position = UDim2.new(0, 40, 0, 0),
|
Position = UDim2.new(0, 40, 0, 0),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}),
|
}),
|
||||||
@@ -74,13 +74,13 @@ function ChangesViewer:render()
|
|||||||
Subtitle = e("TextLabel", {
|
Subtitle = e("TextLabel", {
|
||||||
Text = DateTime.fromUnixTimestamp(self.props.patchData.timestamp):FormatLocalTime("LTS", "en-us"),
|
Text = DateTime.fromUnixTimestamp(self.props.patchData.timestamp):FormatLocalTime("LTS", "en-us"),
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Medium,
|
||||||
TextColor3 = theme.SubTextColor,
|
TextColor3 = theme.SubTextColor,
|
||||||
TextTruncate = Enum.TextTruncate.AtEnd,
|
TextTruncate = Enum.TextTruncate.AtEnd,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
Size = UDim2.new(1, -40, 0, 16),
|
Size = UDim2.new(1, -40, 0, theme.TextSize.Medium),
|
||||||
Position = UDim2.new(0, 40, 0, 20),
|
Position = UDim2.new(0, 40, 0, theme.TextSize.Large + 2),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@@ -131,8 +131,8 @@ function ChangesViewer:render()
|
|||||||
}),
|
}),
|
||||||
AppliedText = e("TextLabel", {
|
AppliedText = e("TextLabel", {
|
||||||
Text = applied,
|
Text = applied,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = theme.TextColor,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
Size = UDim2.new(0, 0, 1, 0),
|
Size = UDim2.new(0, 0, 1, 0),
|
||||||
@@ -156,8 +156,8 @@ function ChangesViewer:render()
|
|||||||
}),
|
}),
|
||||||
UnappliedText = e("TextLabel", {
|
UnappliedText = e("TextLabel", {
|
||||||
Text = unapplied,
|
Text = unapplied,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = theme.Diff.Warning,
|
TextColor3 = theme.Diff.Warning,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
Size = UDim2.new(0, 0, 1, 0),
|
Size = UDim2.new(0, 0, 1, 0),
|
||||||
@@ -217,13 +217,13 @@ local function ConnectionDetails(props)
|
|||||||
}, {
|
}, {
|
||||||
ProjectName = e("TextLabel", {
|
ProjectName = e("TextLabel", {
|
||||||
Text = props.projectName,
|
Text = props.projectName,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 20,
|
TextSize = theme.TextSize.Large,
|
||||||
TextColor3 = theme.ConnectionDetails.ProjectNameColor,
|
TextColor3 = theme.ConnectionDetails.ProjectNameColor,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
|
|
||||||
Size = UDim2.new(1, 0, 0, 20),
|
Size = UDim2.new(1, 0, 0, theme.TextSize.Large),
|
||||||
|
|
||||||
LayoutOrder = 1,
|
LayoutOrder = 1,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
@@ -231,13 +231,13 @@ local function ConnectionDetails(props)
|
|||||||
|
|
||||||
Address = e("TextLabel", {
|
Address = e("TextLabel", {
|
||||||
Text = props.address,
|
Text = props.address,
|
||||||
Font = Enum.Font.Code,
|
FontFace = theme.Font.Code,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Medium,
|
||||||
TextColor3 = theme.ConnectionDetails.AddressColor,
|
TextColor3 = theme.ConnectionDetails.AddressColor,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
|
|
||||||
Size = UDim2.new(1, 0, 0, 15),
|
Size = UDim2.new(1, 0, 0, theme.TextSize.Medium),
|
||||||
|
|
||||||
LayoutOrder = 2,
|
LayoutOrder = 2,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
@@ -410,8 +410,8 @@ function ConnectedPage:render()
|
|||||||
Text = e("TextLabel", {
|
Text = e("TextLabel", {
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Text = self.changeInfoText,
|
Text = self.changeInfoText,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 15,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = if syncWarning then theme.Diff.Warning else theme.Header.VersionColor,
|
TextColor3 = if syncWarning then theme.Diff.Warning else theme.Header.VersionColor,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
TextXAlignment = Enum.TextXAlignment.Right,
|
TextXAlignment = Enum.TextXAlignment.Right,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
local Plugin = Rojo.Plugin
|
local Plugin = Rojo.Plugin
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
@@ -7,6 +5,7 @@ local Packages = Rojo.Packages
|
|||||||
local Roact = require(Packages.Roact)
|
local Roact = require(Packages.Roact)
|
||||||
|
|
||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local TextButton = require(Plugin.App.Components.TextButton)
|
local TextButton = require(Plugin.App.Components.TextButton)
|
||||||
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
|
||||||
@@ -24,6 +23,7 @@ function Error:init()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Error:render()
|
function Error:render()
|
||||||
|
return Theme.with(function(theme)
|
||||||
return e(BorderedContainer, {
|
return e(BorderedContainer, {
|
||||||
size = Roact.joinBindings({
|
size = Roact.joinBindings({
|
||||||
containerSize = self.props.containerSize,
|
containerSize = self.props.containerSize,
|
||||||
@@ -49,18 +49,17 @@ function Error:render()
|
|||||||
[Roact.Change.AbsoluteSize] = function(object)
|
[Roact.Change.AbsoluteSize] = function(object)
|
||||||
local containerSize = object.AbsoluteSize - ERROR_PADDING * 2
|
local containerSize = object.AbsoluteSize - ERROR_PADDING * 2
|
||||||
|
|
||||||
local textBounds = TextService:GetTextSize(
|
local textBounds = getTextBoundsAsync(
|
||||||
self.props.errorMessage,
|
self.props.errorMessage,
|
||||||
16,
|
theme.Font.Code,
|
||||||
Enum.Font.Code,
|
theme.TextSize.Code,
|
||||||
Vector2.new(containerSize.X, math.huge)
|
containerSize.X
|
||||||
)
|
)
|
||||||
|
|
||||||
self.setContentSize(Vector2.new(containerSize.X, textBounds.Y))
|
self.setContentSize(Vector2.new(containerSize.X, textBounds.Y))
|
||||||
end,
|
end,
|
||||||
}, {
|
}, {
|
||||||
ErrorMessage = Theme.with(function(theme)
|
ErrorMessage = e("TextBox", {
|
||||||
return e("TextBox", {
|
|
||||||
[Roact.Event.InputBegan] = function(rbx, input)
|
[Roact.Event.InputBegan] = function(rbx, input)
|
||||||
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then
|
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then
|
||||||
return
|
return
|
||||||
@@ -71,8 +70,8 @@ function Error:render()
|
|||||||
|
|
||||||
Text = self.props.errorMessage,
|
Text = self.props.errorMessage,
|
||||||
TextEditable = false,
|
TextEditable = false,
|
||||||
Font = Enum.Font.Code,
|
FontFace = theme.Font.Code,
|
||||||
TextSize = 16,
|
TextSize = theme.TextSize.Code,
|
||||||
TextColor3 = theme.ErrorColor,
|
TextColor3 = theme.ErrorColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextYAlignment = Enum.TextYAlignment.Top,
|
TextYAlignment = Enum.TextYAlignment.Top,
|
||||||
@@ -81,8 +80,7 @@ function Error:render()
|
|||||||
ClearTextOnFocus = false,
|
ClearTextOnFocus = false,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
Size = UDim2.new(1, 0, 1, 0),
|
Size = UDim2.new(1, 0, 1, 0),
|
||||||
})
|
}),
|
||||||
end),
|
|
||||||
|
|
||||||
Padding = e("UIPadding", {
|
Padding = e("UIPadding", {
|
||||||
PaddingLeft = UDim.new(0, ERROR_PADDING.X),
|
PaddingLeft = UDim.new(0, ERROR_PADDING.X),
|
||||||
@@ -92,6 +90,7 @@ function Error:render()
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local ErrorPage = Roact.Component:extend("ErrorPage")
|
local ErrorPage = Roact.Component:extend("ErrorPage")
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ local function AddressEntry(props)
|
|||||||
}, {
|
}, {
|
||||||
Host = e("TextBox", {
|
Host = e("TextBox", {
|
||||||
Text = props.host or "",
|
Text = props.host or "",
|
||||||
Font = Enum.Font.Code,
|
FontFace = theme.Font.Code,
|
||||||
TextSize = 18,
|
TextSize = theme.TextSize.Large,
|
||||||
TextColor3 = theme.AddressEntry.TextColor,
|
TextColor3 = theme.AddressEntry.TextColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
@@ -51,8 +51,8 @@ local function AddressEntry(props)
|
|||||||
|
|
||||||
Port = e("TextBox", {
|
Port = e("TextBox", {
|
||||||
Text = props.port or "",
|
Text = props.port or "",
|
||||||
Font = Enum.Font.Code,
|
FontFace = theme.Font.Code,
|
||||||
TextSize = 18,
|
TextSize = theme.TextSize.Large,
|
||||||
TextColor3 = theme.AddressEntry.TextColor,
|
TextColor3 = theme.AddressEntry.TextColor,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
PlaceholderText = Config.defaultPort,
|
PlaceholderText = Config.defaultPort,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
local TextService = game:GetService("TextService")
|
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
local Plugin = Rojo.Plugin
|
local Plugin = Rojo.Plugin
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
@@ -9,6 +7,7 @@ local Roact = require(Packages.Roact)
|
|||||||
local Settings = require(Plugin.Settings)
|
local Settings = require(Plugin.Settings)
|
||||||
local Assets = require(Plugin.Assets)
|
local Assets = require(Plugin.Assets)
|
||||||
local Theme = require(Plugin.App.Theme)
|
local Theme = require(Plugin.App.Theme)
|
||||||
|
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
|
||||||
|
|
||||||
local Checkbox = require(Plugin.App.Components.Checkbox)
|
local Checkbox = require(Plugin.App.Components.Checkbox)
|
||||||
local Dropdown = require(Plugin.App.Components.Dropdown)
|
local Dropdown = require(Plugin.App.Components.Dropdown)
|
||||||
@@ -31,10 +30,16 @@ local TAG_TYPES = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local function getTextBounds(text, textSize, font, lineHeight, bounds)
|
local function getTextBoundsWithLineHeight(
|
||||||
local textBounds = TextService:GetTextSize(text, textSize, font, bounds)
|
text: string,
|
||||||
|
font: Font,
|
||||||
|
textSize: number,
|
||||||
|
width: number,
|
||||||
|
lineHeight: number
|
||||||
|
)
|
||||||
|
local textBounds = getTextBoundsAsync(text, font, textSize, width)
|
||||||
|
|
||||||
local lineCount = textBounds.Y / textSize
|
local lineCount = math.ceil(textBounds.Y / textSize)
|
||||||
local lineHeightAbsolute = textSize * lineHeight
|
local lineHeightAbsolute = textSize * lineHeight
|
||||||
|
|
||||||
return Vector2.new(textBounds.X, lineHeightAbsolute * lineCount - (lineHeightAbsolute - textSize))
|
return Vector2.new(textBounds.X, lineHeightAbsolute * lineCount - (lineHeightAbsolute - textSize))
|
||||||
@@ -109,6 +114,7 @@ function Setting:render()
|
|||||||
then self.props.input
|
then self.props.input
|
||||||
elseif self.props.options ~= nil then e(Dropdown, {
|
elseif self.props.options ~= nil then e(Dropdown, {
|
||||||
locked = self.props.locked,
|
locked = self.props.locked,
|
||||||
|
lockedTooltip = self.props.lockedTooltip,
|
||||||
options = self.props.options,
|
options = self.props.options,
|
||||||
active = self.state.setting,
|
active = self.state.setting,
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
@@ -118,6 +124,7 @@ function Setting:render()
|
|||||||
})
|
})
|
||||||
else e(Checkbox, {
|
else e(Checkbox, {
|
||||||
locked = self.props.locked,
|
locked = self.props.locked,
|
||||||
|
lockedTooltip = self.props.lockedTooltip,
|
||||||
active = self.state.setting,
|
active = self.state.setting,
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
onClick = function()
|
onClick = function()
|
||||||
@@ -145,7 +152,7 @@ function Setting:render()
|
|||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}, {
|
}, {
|
||||||
Heading = e("Frame", {
|
Heading = e("Frame", {
|
||||||
Size = UDim2.new(1, 0, 0, 16),
|
Size = UDim2.new(1, 0, 0, theme.TextSize.Medium),
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
}, {
|
}, {
|
||||||
Layout = e("UIListLayout", {
|
Layout = e("UIListLayout", {
|
||||||
@@ -165,8 +172,8 @@ function Setting:render()
|
|||||||
else nil,
|
else nil,
|
||||||
Name = e("TextLabel", {
|
Name = e("TextLabel", {
|
||||||
Text = self.props.name,
|
Text = self.props.name,
|
||||||
Font = Enum.Font.GothamBold,
|
FontFace = theme.Font.Bold,
|
||||||
TextSize = 16,
|
TextSize = theme.TextSize.Medium,
|
||||||
TextColor3 = if self.props.tag and TAG_TYPES[self.props.tag]
|
TextColor3 = if self.props.tag and TAG_TYPES[self.props.tag]
|
||||||
then getThemeColorFromPath(theme, TAG_TYPES[self.props.tag].color)
|
then getThemeColorFromPath(theme, TAG_TYPES[self.props.tag].color)
|
||||||
else settingsTheme.Setting.NameColor,
|
else settingsTheme.Setting.NameColor,
|
||||||
@@ -174,7 +181,7 @@ function Setting:render()
|
|||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
RichText = true,
|
RichText = true,
|
||||||
|
|
||||||
Size = UDim2.new(1, 0, 0, 16),
|
Size = UDim2.new(1, 0, 0, theme.TextSize.Medium),
|
||||||
|
|
||||||
LayoutOrder = 2,
|
LayoutOrder = 2,
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
@@ -183,9 +190,9 @@ function Setting:render()
|
|||||||
|
|
||||||
Description = e("TextLabel", {
|
Description = e("TextLabel", {
|
||||||
Text = self.props.description,
|
Text = self.props.description,
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Main,
|
||||||
LineHeight = 1.2,
|
LineHeight = 1.2,
|
||||||
TextSize = 14,
|
TextSize = theme.TextSize.Body,
|
||||||
TextColor3 = settingsTheme.Setting.DescriptionColor,
|
TextColor3 = settingsTheme.Setting.DescriptionColor,
|
||||||
TextXAlignment = Enum.TextXAlignment.Left,
|
TextXAlignment = Enum.TextXAlignment.Left,
|
||||||
TextTransparency = self.props.transparency,
|
TextTransparency = self.props.transparency,
|
||||||
@@ -197,12 +204,12 @@ function Setting:render()
|
|||||||
inputSize = self.inputSize,
|
inputSize = self.inputSize,
|
||||||
}):map(function(values)
|
}):map(function(values)
|
||||||
local offset = values.inputSize.X + 5
|
local offset = values.inputSize.X + 5
|
||||||
local textBounds = getTextBounds(
|
local textBounds = getTextBoundsWithLineHeight(
|
||||||
self.props.description,
|
self.props.description,
|
||||||
14,
|
theme.Font.Main,
|
||||||
Enum.Font.Gotham,
|
theme.TextSize.Body,
|
||||||
1.2,
|
values.containerSize.X - offset,
|
||||||
Vector2.new(values.containerSize.X - offset, math.huge)
|
1.2
|
||||||
)
|
)
|
||||||
return UDim2.new(1, -offset, 0, textBounds.Y)
|
return UDim2.new(1, -offset, 0, textBounds.Y)
|
||||||
end),
|
end),
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ local confirmationBehaviors = { "Initial", "Always", "Large Changes", "Unlisted
|
|||||||
|
|
||||||
local function Navbar(props)
|
local function Navbar(props)
|
||||||
return Theme.with(function(theme)
|
return Theme.with(function(theme)
|
||||||
theme = theme.Settings.Navbar
|
local navbarTheme = theme.Settings.Navbar
|
||||||
|
|
||||||
return e("Frame", {
|
return e("Frame", {
|
||||||
Size = UDim2.new(1, 0, 0, 46),
|
Size = UDim2.new(1, 0, 0, 46),
|
||||||
@@ -40,7 +40,7 @@ local function Navbar(props)
|
|||||||
Back = e(IconButton, {
|
Back = e(IconButton, {
|
||||||
icon = Assets.Images.Icons.Back,
|
icon = Assets.Images.Icons.Back,
|
||||||
iconSize = 24,
|
iconSize = 24,
|
||||||
color = theme.BackButtonColor,
|
color = navbarTheme.BackButtonColor,
|
||||||
transparency = props.transparency,
|
transparency = props.transparency,
|
||||||
|
|
||||||
position = UDim2.new(0, 0, 0.5, 0),
|
position = UDim2.new(0, 0, 0.5, 0),
|
||||||
@@ -55,9 +55,9 @@ local function Navbar(props)
|
|||||||
|
|
||||||
Text = e("TextLabel", {
|
Text = e("TextLabel", {
|
||||||
Text = "Settings",
|
Text = "Settings",
|
||||||
Font = Enum.Font.Gotham,
|
FontFace = theme.Font.Thin,
|
||||||
TextSize = 18,
|
TextSize = theme.TextSize.Large,
|
||||||
TextColor3 = theme.TextColor,
|
TextColor3 = navbarTheme.TextColor,
|
||||||
TextTransparency = props.transparency,
|
TextTransparency = props.transparency,
|
||||||
|
|
||||||
Size = UDim2.new(1, 0, 1, 0),
|
Size = UDim2.new(1, 0, 1, 0),
|
||||||
@@ -81,9 +81,6 @@ function SettingsPage:render()
|
|||||||
return layoutOrder
|
return layoutOrder
|
||||||
end
|
end
|
||||||
|
|
||||||
return Theme.with(function(theme)
|
|
||||||
theme = theme.Settings
|
|
||||||
|
|
||||||
return Roact.createFragment({
|
return Roact.createFragment({
|
||||||
Navbar = e(Navbar, {
|
Navbar = e(Navbar, {
|
||||||
onBack = self.props.onBack,
|
onBack = self.props.onBack,
|
||||||
@@ -204,6 +201,7 @@ function SettingsPage:render()
|
|||||||
name = "Two-Way Sync",
|
name = "Two-Way Sync",
|
||||||
description = "Editing files in Studio will sync them into the filesystem",
|
description = "Editing files in Studio will sync them into the filesystem",
|
||||||
locked = self.props.syncActive,
|
locked = self.props.syncActive,
|
||||||
|
lockedTooltip = "(Cannot change while currently syncing. Disconnect first.)",
|
||||||
tag = "unstable",
|
tag = "unstable",
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
layoutOrder = layoutIncrement(),
|
layoutOrder = layoutIncrement(),
|
||||||
@@ -259,7 +257,6 @@ function SettingsPage:render()
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return SettingsPage
|
return SettingsPage
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
--[[
|
--[[
|
||||||
Theming system taking advantage of Roact's new context API.
|
Theming system provided through Roact's context.
|
||||||
Doesn't use colors provided by Studio and instead just branches on theme
|
Uses Studio colors when possible.
|
||||||
name. This isn't exactly best practice.
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
-- Studio does not exist outside Roblox Studio, so we'll lazily initialize it
|
-- Studio does not exist outside Roblox Studio, so we'll lazily initialize it
|
||||||
@@ -15,6 +14,8 @@ local function getStudio()
|
|||||||
return _Studio
|
return _Studio
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local ContentProvider = game:GetService("ContentProvider")
|
||||||
|
|
||||||
local Rojo = script:FindFirstAncestor("Rojo")
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
local Packages = Rojo.Packages
|
local Packages = Rojo.Packages
|
||||||
|
|
||||||
@@ -35,6 +36,27 @@ function StudioProvider:updateTheme()
|
|||||||
local isDark = studioTheme.Name == "Dark"
|
local isDark = studioTheme.Name == "Dark"
|
||||||
|
|
||||||
local theme = strict(studioTheme.Name .. "Theme", {
|
local theme = strict(studioTheme.Name .. "Theme", {
|
||||||
|
Font = {
|
||||||
|
Main = Font.new("rbxasset://fonts/families/Montserrat.json", Enum.FontWeight.Medium, Enum.FontStyle.Normal),
|
||||||
|
Bold = Font.new("rbxasset://fonts/families/Montserrat.json", Enum.FontWeight.Bold, Enum.FontStyle.Normal),
|
||||||
|
Thin = Font.new(
|
||||||
|
"rbxasset://fonts/families/Montserrat.json",
|
||||||
|
Enum.FontWeight.Regular,
|
||||||
|
Enum.FontStyle.Normal
|
||||||
|
),
|
||||||
|
Code = Font.new(
|
||||||
|
"rbxasset://fonts/families/Inconsolata.json",
|
||||||
|
Enum.FontWeight.Regular,
|
||||||
|
Enum.FontStyle.Normal
|
||||||
|
),
|
||||||
|
},
|
||||||
|
TextSize = {
|
||||||
|
Body = 15,
|
||||||
|
Small = 13,
|
||||||
|
Medium = 16,
|
||||||
|
Large = 18,
|
||||||
|
Code = 16,
|
||||||
|
},
|
||||||
BrandColor = BRAND_COLOR,
|
BrandColor = BRAND_COLOR,
|
||||||
BackgroundColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainBackground),
|
BackgroundColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainBackground),
|
||||||
TextColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainText),
|
TextColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainText),
|
||||||
@@ -190,6 +212,13 @@ end
|
|||||||
|
|
||||||
function StudioProvider:init()
|
function StudioProvider:init()
|
||||||
self:updateTheme()
|
self:updateTheme()
|
||||||
|
|
||||||
|
-- Preload the Fonts so that getTextBoundsAsync won't yield
|
||||||
|
local fontAssetIds = {}
|
||||||
|
for _, font in self.state.theme.Font do
|
||||||
|
table.insert(fontAssetIds, font.Family)
|
||||||
|
end
|
||||||
|
pcall(ContentProvider.PreloadAsync, ContentProvider, fontAssetIds)
|
||||||
end
|
end
|
||||||
|
|
||||||
function StudioProvider:render()
|
function StudioProvider:render()
|
||||||
|
|||||||
41
plugin/src/App/getTextBoundsAsync.lua
Normal file
41
plugin/src/App/getTextBoundsAsync.lua
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
local TextService = game:GetService("TextService")
|
||||||
|
|
||||||
|
local Rojo = script:FindFirstAncestor("Rojo")
|
||||||
|
local Packages = Rojo.Packages
|
||||||
|
|
||||||
|
local Log = require(Packages.Log)
|
||||||
|
|
||||||
|
local params = Instance.new("GetTextBoundsParams")
|
||||||
|
|
||||||
|
local function getTextBoundsAsync(
|
||||||
|
text: string,
|
||||||
|
font: Font,
|
||||||
|
textSize: number,
|
||||||
|
width: number,
|
||||||
|
richText: boolean?
|
||||||
|
): Vector2
|
||||||
|
if type(text) ~= "string" then
|
||||||
|
Log.warn(`Invalid text. Expected string, received {type(text)} instead`)
|
||||||
|
return Vector2.zero
|
||||||
|
end
|
||||||
|
if #text >= 200_000 then
|
||||||
|
Log.warn(`Invalid text. Exceeds the 199,999 character limit`)
|
||||||
|
return Vector2.zero
|
||||||
|
end
|
||||||
|
|
||||||
|
params.Text = text
|
||||||
|
params.Font = font
|
||||||
|
params.Size = textSize
|
||||||
|
params.Width = width
|
||||||
|
params.RichText = not not richText
|
||||||
|
|
||||||
|
local success, bounds = pcall(TextService.GetTextBoundsAsync, TextService, params)
|
||||||
|
if not success then
|
||||||
|
Log.warn(`Failed to get text bounds: {bounds}`)
|
||||||
|
return Vector2.zero
|
||||||
|
end
|
||||||
|
|
||||||
|
return bounds
|
||||||
|
end
|
||||||
|
|
||||||
|
return getTextBoundsAsync
|
||||||
@@ -52,9 +52,9 @@ local App = Roact.Component:extend("App")
|
|||||||
function App:init()
|
function App:init()
|
||||||
preloadAssets()
|
preloadAssets()
|
||||||
|
|
||||||
local priorHost, priorPort = self:getPriorEndpoint()
|
local priorSyncInfo = self:getPriorSyncInfo()
|
||||||
self.host, self.setHost = Roact.createBinding(priorHost or "")
|
self.host, self.setHost = Roact.createBinding(priorSyncInfo.host or "")
|
||||||
self.port, self.setPort = Roact.createBinding(priorPort or "")
|
self.port, self.setPort = Roact.createBinding(priorSyncInfo.port or "")
|
||||||
|
|
||||||
self.confirmationBindable = Instance.new("BindableEvent")
|
self.confirmationBindable = Instance.new("BindableEvent")
|
||||||
self.confirmationEvent = self.confirmationBindable.Event
|
self.confirmationEvent = self.confirmationBindable.Event
|
||||||
@@ -145,10 +145,19 @@ function App:init()
|
|||||||
if
|
if
|
||||||
Settings:get("syncReminder")
|
Settings:get("syncReminder")
|
||||||
and self.serveSession == nil
|
and self.serveSession == nil
|
||||||
and self:getLastSyncTimestamp()
|
and self:getPriorSyncInfo().timestamp ~= nil
|
||||||
and (self:isSyncLockAvailable())
|
and (self:isSyncLockAvailable())
|
||||||
then
|
then
|
||||||
self:addNotification("You've previously synced this place. Would you like to reconnect?", 300, {
|
local syncInfo = self:getPriorSyncInfo()
|
||||||
|
local timeSinceSync = timeUtil.elapsedToText(os.time() - syncInfo.timestamp)
|
||||||
|
local syncDetail = if syncInfo.projectName
|
||||||
|
then `project '{syncInfo.projectName}'`
|
||||||
|
else `{syncInfo.host or Config.defaultHost}:{syncInfo.port or Config.defaultPort}`
|
||||||
|
|
||||||
|
self:addNotification(
|
||||||
|
`You synced {syncDetail} to this place {timeSinceSync}. Would you like to reconnect?`,
|
||||||
|
300,
|
||||||
|
{
|
||||||
Connect = {
|
Connect = {
|
||||||
text = "Connect",
|
text = "Connect",
|
||||||
style = "Solid",
|
style = "Solid",
|
||||||
@@ -166,7 +175,8 @@ function App:init()
|
|||||||
notification:dismiss()
|
notification:dismiss()
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -274,54 +284,32 @@ function App:checkForUpdates()
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function App:getPriorEndpoint()
|
function App:getPriorSyncInfo(): { host: string?, port: string?, projectName: string?, timestamp: number? }
|
||||||
local priorEndpoints = Settings:get("priorEndpoints")
|
local priorSyncInfos = Settings:get("priorEndpoints")
|
||||||
if not priorEndpoints then
|
if not priorSyncInfos then
|
||||||
return
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local id = tostring(game.PlaceId)
|
local id = tostring(game.PlaceId)
|
||||||
if ignorePlaceIds[id] then
|
if ignorePlaceIds[id] then
|
||||||
return
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local place = priorEndpoints[id]
|
return priorSyncInfos[id] or {}
|
||||||
if not place then
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return place.host, place.port
|
function App:setPriorSyncInfo(host: string, port: string, projectName: string)
|
||||||
|
local priorSyncInfos = Settings:get("priorEndpoints")
|
||||||
|
if not priorSyncInfos then
|
||||||
|
priorSyncInfos = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function App:getLastSyncTimestamp()
|
local now = os.time()
|
||||||
local priorEndpoints = Settings:get("priorEndpoints")
|
|
||||||
if not priorEndpoints then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local id = tostring(game.PlaceId)
|
|
||||||
if ignorePlaceIds[id] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local place = priorEndpoints[id]
|
|
||||||
if not place then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
return place.timestamp
|
|
||||||
end
|
|
||||||
|
|
||||||
function App:setPriorEndpoint(host: string, port: string)
|
|
||||||
local priorEndpoints = Settings:get("priorEndpoints")
|
|
||||||
if not priorEndpoints then
|
|
||||||
priorEndpoints = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Clear any stale saves to avoid disc bloat
|
-- Clear any stale saves to avoid disc bloat
|
||||||
for placeId, endpoint in priorEndpoints do
|
for placeId, syncInfo in priorSyncInfos do
|
||||||
if os.time() - endpoint.timestamp > 12_960_000 then
|
if now - (syncInfo.timestamp or now) > 12_960_000 then
|
||||||
priorEndpoints[placeId] = nil
|
priorSyncInfos[placeId] = nil
|
||||||
Log.trace("Cleared stale saved endpoint for {}", placeId)
|
Log.trace("Cleared stale saved endpoint for {}", placeId)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -331,14 +319,15 @@ function App:setPriorEndpoint(host: string, port: string)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
priorEndpoints[id] = {
|
priorSyncInfos[id] = {
|
||||||
host = if host ~= Config.defaultHost then host else nil,
|
host = if host ~= Config.defaultHost then host else nil,
|
||||||
port = if port ~= Config.defaultPort then port else nil,
|
port = if port ~= Config.defaultPort then port else nil,
|
||||||
timestamp = os.time(),
|
projectName = projectName,
|
||||||
|
timestamp = now,
|
||||||
}
|
}
|
||||||
Log.trace("Saved last used endpoint for {}", game.PlaceId)
|
Log.trace("Saved last used endpoint for {}", game.PlaceId)
|
||||||
|
|
||||||
Settings:set("priorEndpoints", priorEndpoints)
|
Settings:set("priorEndpoints", priorSyncInfos)
|
||||||
end
|
end
|
||||||
|
|
||||||
function App:getHostAndPort()
|
function App:getHostAndPort()
|
||||||
@@ -533,8 +522,6 @@ function App:startSession()
|
|||||||
|
|
||||||
serveSession:onStatusChanged(function(status, details)
|
serveSession:onStatusChanged(function(status, details)
|
||||||
if status == ServeSession.Status.Connecting then
|
if status == ServeSession.Status.Connecting then
|
||||||
self:setPriorEndpoint(host, port)
|
|
||||||
|
|
||||||
self:setState({
|
self:setState({
|
||||||
appStatus = AppStatus.Connecting,
|
appStatus = AppStatus.Connecting,
|
||||||
toolbarIcon = Assets.Images.PluginButton,
|
toolbarIcon = Assets.Images.PluginButton,
|
||||||
@@ -542,6 +529,7 @@ function App:startSession()
|
|||||||
self:addNotification("Connecting to session...")
|
self:addNotification("Connecting to session...")
|
||||||
elseif status == ServeSession.Status.Connected then
|
elseif status == ServeSession.Status.Connected then
|
||||||
self.knownProjects[details] = true
|
self.knownProjects[details] = true
|
||||||
|
self:setPriorSyncInfo(host, port, details)
|
||||||
self:setRunningConnectionInfo(baseUrl)
|
self:setRunningConnectionInfo(baseUrl)
|
||||||
|
|
||||||
local address = ("%s:%s"):format(host, port)
|
local address = ("%s:%s"):format(host, port)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ local invariant = require(script.Parent.Parent.invariant)
|
|||||||
|
|
||||||
local decodeValue = require(script.Parent.decodeValue)
|
local decodeValue = require(script.Parent.decodeValue)
|
||||||
local reify = require(script.Parent.reify)
|
local reify = require(script.Parent.reify)
|
||||||
|
local reifyInstance, applyDeferredRefs = reify.reifyInstance, reify.applyDeferredRefs
|
||||||
local setProperty = require(script.Parent.setProperty)
|
local setProperty = require(script.Parent.setProperty)
|
||||||
|
|
||||||
local function applyPatch(instanceMap, patch)
|
local function applyPatch(instanceMap, patch)
|
||||||
@@ -29,6 +30,11 @@ local function applyPatch(instanceMap, patch)
|
|||||||
-- Tracks any portions of the patch that could not be applied to the DOM.
|
-- Tracks any portions of the patch that could not be applied to the DOM.
|
||||||
local unappliedPatch = PatchSet.newEmpty()
|
local unappliedPatch = PatchSet.newEmpty()
|
||||||
|
|
||||||
|
-- Contains a list of all of the ref properties that we'll need to assign.
|
||||||
|
-- It is imperative that refs are assigned after all instances are created
|
||||||
|
-- to ensure that referents can be mapped to instances correctly.
|
||||||
|
local deferredRefs = {}
|
||||||
|
|
||||||
for _, removedIdOrInstance in ipairs(patch.removed) do
|
for _, removedIdOrInstance in ipairs(patch.removed) do
|
||||||
local removeInstanceSuccess = pcall(function()
|
local removeInstanceSuccess = pcall(function()
|
||||||
if Types.RbxId(removedIdOrInstance) then
|
if Types.RbxId(removedIdOrInstance) then
|
||||||
@@ -78,7 +84,7 @@ local function applyPatch(instanceMap, patch)
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local failedToReify = reify(instanceMap, patch.added, id, parentInstance)
|
local failedToReify = reifyInstance(deferredRefs, instanceMap, patch.added, id, parentInstance)
|
||||||
|
|
||||||
if not PatchSet.isEmpty(failedToReify) then
|
if not PatchSet.isEmpty(failedToReify) then
|
||||||
Log.debug("Failed to reify as part of applying a patch: {:#?}", failedToReify)
|
Log.debug("Failed to reify as part of applying a patch: {:#?}", failedToReify)
|
||||||
@@ -143,7 +149,7 @@ local function applyPatch(instanceMap, patch)
|
|||||||
[update.id] = mockVirtualInstance,
|
[update.id] = mockVirtualInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
local failedToReify = reify(instanceMap, mockAdded, update.id, instance.Parent)
|
local failedToReify = reifyInstance(deferredRefs, instanceMap, mockAdded, update.id, instance.Parent)
|
||||||
|
|
||||||
local newInstance = instanceMap.fromIds[update.id]
|
local newInstance = instanceMap.fromIds[update.id]
|
||||||
|
|
||||||
@@ -206,6 +212,18 @@ local function applyPatch(instanceMap, patch)
|
|||||||
|
|
||||||
if update.changedProperties ~= nil then
|
if update.changedProperties ~= nil then
|
||||||
for propertyName, propertyValue in pairs(update.changedProperties) do
|
for propertyName, propertyValue in pairs(update.changedProperties) do
|
||||||
|
-- Because refs may refer to instances that we haven't constructed yet,
|
||||||
|
-- we defer applying any ref properties until all instances are created.
|
||||||
|
if next(propertyValue) == "Ref" then
|
||||||
|
table.insert(deferredRefs, {
|
||||||
|
id = update.id,
|
||||||
|
instance = instance,
|
||||||
|
propertyName = propertyName,
|
||||||
|
virtualValue = propertyValue,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
local decodeSuccess, decodedValue = decodeValue(propertyValue, instanceMap)
|
local decodeSuccess, decodedValue = decodeValue(propertyValue, instanceMap)
|
||||||
if not decodeSuccess then
|
if not decodeSuccess then
|
||||||
unappliedUpdate.changedProperties[propertyName] = propertyValue
|
unappliedUpdate.changedProperties[propertyName] = propertyValue
|
||||||
@@ -230,6 +248,8 @@ local function applyPatch(instanceMap, patch)
|
|||||||
ChangeHistoryService:FinishRecording(historyRecording, Enum.FinishRecordingOperation.Commit)
|
ChangeHistoryService:FinishRecording(historyRecording, Enum.FinishRecordingOperation.Commit)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
return unappliedPatch
|
return unappliedPatch
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,24 @@ local function diff(instanceMap, virtualInstances, rootId)
|
|||||||
|
|
||||||
if getProperySuccess then
|
if getProperySuccess then
|
||||||
local existingValue = existingValueOrErr
|
local existingValue = existingValueOrErr
|
||||||
local decodeSuccess, decodedValue = decodeValue(virtualValue, instanceMap)
|
local decodeSuccess, decodedValue
|
||||||
|
|
||||||
|
-- If `virtualValue` is a ref then instead of decoding it to an instance,
|
||||||
|
-- we change `existingValue` to be a ref. This is because `virtualValue`
|
||||||
|
-- may point to an Instance which doesn't exist yet and therefore
|
||||||
|
-- decoding it may throw an error.
|
||||||
|
if next(virtualValue) == "Ref" then
|
||||||
|
decodeSuccess, decodedValue = true, virtualValue
|
||||||
|
|
||||||
|
if existingValue and typeof(existingValue) == "Instance" then
|
||||||
|
local existingValueRef = instanceMap.fromInstances[existingValue]
|
||||||
|
if existingValueRef then
|
||||||
|
existingValue = { Ref = existingValueRef }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
decodeSuccess, decodedValue = decodeValue(virtualValue, instanceMap)
|
||||||
|
end
|
||||||
|
|
||||||
if decodeSuccess then
|
if decodeSuccess then
|
||||||
if not trueEquals(existingValue, decodedValue) then
|
if not trueEquals(existingValue, decodedValue) then
|
||||||
|
|||||||
@@ -7,26 +7,6 @@ local PatchSet = require(script.Parent.Parent.PatchSet)
|
|||||||
local setProperty = require(script.Parent.setProperty)
|
local setProperty = require(script.Parent.setProperty)
|
||||||
local decodeValue = require(script.Parent.decodeValue)
|
local decodeValue = require(script.Parent.decodeValue)
|
||||||
|
|
||||||
local reifyInner, applyDeferredRefs
|
|
||||||
|
|
||||||
local function reify(instanceMap, virtualInstances, rootId, parentInstance)
|
|
||||||
-- Create an empty patch that will be populated with any parts of this reify
|
|
||||||
-- that could not happen, like instances that couldn't be created and
|
|
||||||
-- properties that could not be assigned.
|
|
||||||
local unappliedPatch = PatchSet.newEmpty()
|
|
||||||
|
|
||||||
-- Contains a list of all of the ref properties that we'll need to assign
|
|
||||||
-- after all instances are created. We apply refs in a second pass, after
|
|
||||||
-- we create as many instances as we can, so that we ensure that referents
|
|
||||||
-- can be mapped to instances correctly.
|
|
||||||
local deferredRefs = {}
|
|
||||||
|
|
||||||
reifyInner(instanceMap, virtualInstances, rootId, parentInstance, unappliedPatch, deferredRefs)
|
|
||||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
|
||||||
|
|
||||||
return unappliedPatch
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Add the given ID and all of its descendants in virtualInstances to the given
|
Add the given ID and all of its descendants in virtualInstances to the given
|
||||||
PatchSet, marked for addition.
|
PatchSet, marked for addition.
|
||||||
@@ -40,10 +20,21 @@ local function addAllToPatch(patchSet, virtualInstances, id)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function reifyInstance(deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
|
||||||
|
-- Create an empty patch that will be populated with any parts of this reify
|
||||||
|
-- that could not happen, like instances that couldn't be created and
|
||||||
|
-- properties that could not be assigned.
|
||||||
|
local unappliedPatch = PatchSet.newEmpty()
|
||||||
|
|
||||||
|
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
|
||||||
|
|
||||||
|
return unappliedPatch
|
||||||
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Inner function that defines the core routine.
|
Inner function that defines the core routine.
|
||||||
]]
|
]]
|
||||||
function reifyInner(instanceMap, virtualInstances, id, parentInstance, unappliedPatch, deferredRefs)
|
function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, id, parentInstance)
|
||||||
local virtualInstance = virtualInstances[id]
|
local virtualInstance = virtualInstances[id]
|
||||||
|
|
||||||
if virtualInstance == nil then
|
if virtualInstance == nil then
|
||||||
@@ -102,7 +93,7 @@ function reifyInner(instanceMap, virtualInstances, id, parentInstance, unapplied
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _, childId in ipairs(virtualInstance.Children) do
|
for _, childId in ipairs(virtualInstance.Children) do
|
||||||
reifyInner(instanceMap, virtualInstances, childId, instance, unappliedPatch, deferredRefs)
|
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, childId, instance)
|
||||||
end
|
end
|
||||||
|
|
||||||
instance.Parent = parentInstance
|
instance.Parent = parentInstance
|
||||||
@@ -143,6 +134,7 @@ function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local targetInstance = instanceMap.fromIds[refId]
|
local targetInstance = instanceMap.fromIds[refId]
|
||||||
|
|
||||||
if targetInstance == nil then
|
if targetInstance == nil then
|
||||||
markFailed(entry.id, entry.propertyName, entry.virtualValue)
|
markFailed(entry.id, entry.propertyName, entry.virtualValue)
|
||||||
continue
|
continue
|
||||||
@@ -155,4 +147,7 @@ function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return reify
|
return {
|
||||||
|
reifyInstance = reifyInstance,
|
||||||
|
applyDeferredRefs = applyDeferredRefs,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
return function()
|
return function()
|
||||||
local reify = require(script.Parent.reify)
|
local reify = require(script.Parent.reify)
|
||||||
|
local reifyInstance, applyDeferredRefs = reify.reifyInstance, reify.applyDeferredRefs
|
||||||
|
|
||||||
local PatchSet = require(script.Parent.Parent.PatchSet)
|
local PatchSet = require(script.Parent.Parent.PatchSet)
|
||||||
local InstanceMap = require(script.Parent.Parent.InstanceMap)
|
local InstanceMap = require(script.Parent.Parent.InstanceMap)
|
||||||
@@ -20,7 +21,11 @@ return function()
|
|||||||
|
|
||||||
it("should throw when given a bogus ID", function()
|
it("should throw when given a bogus ID", function()
|
||||||
expect(function()
|
expect(function()
|
||||||
reify(InstanceMap.new(), {}, "Hi, mom!", game)
|
local deferredRefs = {}
|
||||||
|
local instanceMap = InstanceMap.new()
|
||||||
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, {}, "Hi, mom!", game)
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
end).to.throw()
|
end).to.throw()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -34,8 +39,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT", nil)
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT", nil)
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(instanceMap:size() == 0, "expected instanceMap to be empty")
|
assert(instanceMap:size() == 0, "expected instanceMap to be empty")
|
||||||
|
|
||||||
@@ -60,8 +68,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||||
|
|
||||||
@@ -90,8 +101,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||||
|
|
||||||
@@ -122,8 +136,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
expect(size(unappliedPatch.added)).to.equal(1)
|
expect(size(unappliedPatch.added)).to.equal(1)
|
||||||
expect(unappliedPatch.added["CHILD"]).to.equal(virtualInstances["CHILD"])
|
expect(unappliedPatch.added["CHILD"]).to.equal(virtualInstances["CHILD"])
|
||||||
@@ -153,8 +170,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
local instance = instanceMap.fromIds["ROOT"]
|
local instance = instanceMap.fromIds["ROOT"]
|
||||||
expect(instance.ClassName).to.equal("StringValue")
|
expect(instance.ClassName).to.equal("StringValue")
|
||||||
@@ -196,8 +216,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||||
|
|
||||||
@@ -223,13 +246,16 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
|
|
||||||
local existing = Instance.new("Folder")
|
local existing = Instance.new("Folder")
|
||||||
existing.Name = "Existing"
|
existing.Name = "Existing"
|
||||||
instanceMap:insert("EXISTING", existing)
|
instanceMap:insert("EXISTING", existing)
|
||||||
|
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||||
|
|
||||||
@@ -268,8 +294,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||||
|
|
||||||
@@ -307,8 +336,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||||
|
|
||||||
@@ -332,8 +364,11 @@ return function()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local deferredRefs = {}
|
||||||
local instanceMap = InstanceMap.new()
|
local instanceMap = InstanceMap.new()
|
||||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||||
|
|
||||||
|
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||||
|
|
||||||
assert(not PatchSet.hasRemoves(unappliedPatch), "expected no removes")
|
assert(not PatchSet.hasRemoves(unappliedPatch), "expected no removes")
|
||||||
assert(not PatchSet.hasAdditions(unappliedPatch), "expected no additions")
|
assert(not PatchSet.hasAdditions(unappliedPatch), "expected no additions")
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
rojo build test-place.project.json -o TestPlace.rbxlx
|
|
||||||
run-in-roblox --script run-tests.server.lua --place TestPlace.rbxlx
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
"ReplicatedStorage": {
|
"ReplicatedStorage": {
|
||||||
"Rojo": {
|
"Rojo": {
|
||||||
"$path": "default.project.json"
|
"$path": "../plugin.project.json"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Packages": {
|
"Packages": {
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Continously build the rojo plugin into the local plugin directory on Windows
|
|
||||||
rojo build plugin/default.project.json -o $LOCALAPPDATA/Roblox/Plugins/Rojo.rbxm --watch
|
|
||||||
@@ -6,6 +6,7 @@ expression: contents
|
|||||||
<Item class="Model" referent="0">
|
<Item class="Model" referent="0">
|
||||||
<Properties>
|
<Properties>
|
||||||
<string name="Name">init_meta_class_name</string>
|
<string name="Name">init_meta_class_name</string>
|
||||||
|
<bool name="NeedsPivotMigration">false</bool>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Item>
|
</Item>
|
||||||
</roblox>
|
</roblox>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/build.rs
|
source: tests/tests/build.rs
|
||||||
expression: contents
|
expression: contents
|
||||||
|
|
||||||
---
|
---
|
||||||
<roblox version="4">
|
<roblox version="4">
|
||||||
<Item class="Folder" referent="0">
|
<Item class="Folder" referent="0">
|
||||||
@@ -25,6 +24,7 @@ expression: contents
|
|||||||
<R21>0</R21>
|
<R21>0</R21>
|
||||||
<R22>1</R22>
|
<R22>1</R22>
|
||||||
</CoordinateFrame>
|
</CoordinateFrame>
|
||||||
|
<bool name="NeedsPivotMigration">false</bool>
|
||||||
<Ref name="PrimaryPart">null</Ref>
|
<Ref name="PrimaryPart">null</Ref>
|
||||||
<BinaryString name="Tags"></BinaryString>
|
<BinaryString name="Tags"></BinaryString>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/build.rs
|
source: tests/tests/build.rs
|
||||||
expression: contents
|
expression: contents
|
||||||
|
|
||||||
---
|
---
|
||||||
<roblox version="4">
|
<roblox version="4">
|
||||||
<Item class="DataModel" referent="0">
|
<Item class="DataModel" referent="0">
|
||||||
@@ -22,6 +21,7 @@ expression: contents
|
|||||||
<Item class="Workspace" referent="2">
|
<Item class="Workspace" referent="2">
|
||||||
<Properties>
|
<Properties>
|
||||||
<string name="Name">Workspace</string>
|
<string name="Name">Workspace</string>
|
||||||
|
<bool name="NeedsPivotMigration">false</bool>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Item class="BoolValue" referent="3">
|
<Item class="BoolValue" referent="3">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
||||||
|
|
||||||
---
|
---
|
||||||
instances:
|
instances:
|
||||||
id-2:
|
id-2:
|
||||||
@@ -22,7 +21,8 @@ instances:
|
|||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: test
|
Name: test
|
||||||
Parent: id-2
|
Parent: id-2
|
||||||
Properties: {}
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
messageCursor: 1
|
messageCursor: 1
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
||||||
|
|
||||||
---
|
---
|
||||||
messageCursor: 1
|
messageCursor: 1
|
||||||
messages:
|
messages:
|
||||||
@@ -14,8 +13,9 @@ messages:
|
|||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: test
|
Name: test
|
||||||
Parent: id-2
|
Parent: id-2
|
||||||
Properties: {}
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
removed: []
|
removed: []
|
||||||
updated: []
|
updated: []
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
source: tests/tests/serve.rs
|
||||||
|
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
||||||
|
---
|
||||||
|
instances:
|
||||||
|
id-2:
|
||||||
|
Children:
|
||||||
|
- id-3
|
||||||
|
ClassName: DataModel
|
||||||
|
Id: id-2
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: pivot_migration
|
||||||
|
Parent: "00000000000000000000000000000000"
|
||||||
|
Properties: {}
|
||||||
|
id-3:
|
||||||
|
Children:
|
||||||
|
- id-4
|
||||||
|
- id-5
|
||||||
|
- id-6
|
||||||
|
ClassName: Workspace
|
||||||
|
Id: id-3
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: Workspace
|
||||||
|
Parent: id-2
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
id-4:
|
||||||
|
Children: []
|
||||||
|
ClassName: Model
|
||||||
|
Id: id-4
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: Model
|
||||||
|
Parent: id-3
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
id-5:
|
||||||
|
Children: []
|
||||||
|
ClassName: Tool
|
||||||
|
Id: id-5
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: false
|
||||||
|
Name: Tool
|
||||||
|
Parent: id-3
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
id-6:
|
||||||
|
Children: []
|
||||||
|
ClassName: Actor
|
||||||
|
Id: id-6
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: Actor
|
||||||
|
Parent: id-3
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
messageCursor: 1
|
||||||
|
sessionId: id-1
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
source: tests/tests/serve.rs
|
||||||
|
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
||||||
|
---
|
||||||
|
messageCursor: 1
|
||||||
|
messages:
|
||||||
|
- added:
|
||||||
|
id-6:
|
||||||
|
Children: []
|
||||||
|
ClassName: Actor
|
||||||
|
Id: id-6
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: Actor
|
||||||
|
Parent: id-3
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
removed: []
|
||||||
|
updated:
|
||||||
|
- changedClassName: ~
|
||||||
|
changedMetadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
changedName: ~
|
||||||
|
changedProperties: {}
|
||||||
|
id: id-3
|
||||||
|
sessionId: id-1
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 316
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 335
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 351
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
source: tests/tests/serve.rs
|
||||||
|
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
||||||
|
---
|
||||||
|
instances:
|
||||||
|
id-2:
|
||||||
|
Children:
|
||||||
|
- id-3
|
||||||
|
ClassName: DataModel
|
||||||
|
Id: id-2
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: pivot_migration
|
||||||
|
Parent: "00000000000000000000000000000000"
|
||||||
|
Properties: {}
|
||||||
|
id-3:
|
||||||
|
Children:
|
||||||
|
- id-4
|
||||||
|
- id-5
|
||||||
|
ClassName: Workspace
|
||||||
|
Id: id-3
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: Workspace
|
||||||
|
Parent: id-2
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
id-4:
|
||||||
|
Children: []
|
||||||
|
ClassName: Model
|
||||||
|
Id: id-4
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: true
|
||||||
|
Name: Model
|
||||||
|
Parent: id-3
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
id-5:
|
||||||
|
Children: []
|
||||||
|
ClassName: Tool
|
||||||
|
Id: id-5
|
||||||
|
Metadata:
|
||||||
|
ignoreUnknownInstances: false
|
||||||
|
Name: Tool
|
||||||
|
Parent: id-3
|
||||||
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
|
messageCursor: 0
|
||||||
|
sessionId: id-1
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
source: tests/tests/serve.rs
|
||||||
|
expression: redactions.redacted_yaml(info)
|
||||||
|
---
|
||||||
|
expectedPlaceIds: ~
|
||||||
|
gameId: ~
|
||||||
|
placeId: ~
|
||||||
|
projectName: pivot_migration
|
||||||
|
protocolVersion: 4
|
||||||
|
rootInstanceId: id-2
|
||||||
|
serverVersion: "[server-version]"
|
||||||
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
@@ -31,6 +31,8 @@ instances:
|
|||||||
Attributes:
|
Attributes:
|
||||||
Rojo_Target_PrimaryPart:
|
Rojo_Target_PrimaryPart:
|
||||||
String: project target
|
String: project target
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
PrimaryPart:
|
PrimaryPart:
|
||||||
Ref: id-9
|
Ref: id-9
|
||||||
id-2:
|
id-2:
|
||||||
@@ -55,7 +57,9 @@ instances:
|
|||||||
ignoreUnknownInstances: true
|
ignoreUnknownInstances: true
|
||||||
Name: Workspace
|
Name: Workspace
|
||||||
Parent: id-2
|
Parent: id-2
|
||||||
Properties: {}
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
id-4:
|
id-4:
|
||||||
Children: []
|
Children: []
|
||||||
ClassName: ObjectValue
|
ClassName: ObjectValue
|
||||||
@@ -124,6 +128,8 @@ instances:
|
|||||||
Attributes:
|
Attributes:
|
||||||
Rojo_Target_PrimaryPart:
|
Rojo_Target_PrimaryPart:
|
||||||
String: model target 2
|
String: model target 2
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
PrimaryPart:
|
PrimaryPart:
|
||||||
Ref: id-7
|
Ref: id-7
|
||||||
id-9:
|
id-9:
|
||||||
@@ -138,4 +144,3 @@ instances:
|
|||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 1
|
messageCursor: 1
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ instances:
|
|||||||
ignoreUnknownInstances: true
|
ignoreUnknownInstances: true
|
||||||
Name: Workspace
|
Name: Workspace
|
||||||
Parent: id-2
|
Parent: id-2
|
||||||
Properties: {}
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
id-4:
|
id-4:
|
||||||
Children: []
|
Children: []
|
||||||
ClassName: ObjectValue
|
ClassName: ObjectValue
|
||||||
@@ -104,6 +106,8 @@ instances:
|
|||||||
Attributes:
|
Attributes:
|
||||||
Rojo_Target_PrimaryPart:
|
Rojo_Target_PrimaryPart:
|
||||||
String: model target
|
String: model target
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
PrimaryPart:
|
PrimaryPart:
|
||||||
Ref: id-7
|
Ref: id-7
|
||||||
id-9:
|
id-9:
|
||||||
@@ -118,4 +122,3 @@ instances:
|
|||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 0
|
messageCursor: 0
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ instances:
|
|||||||
ignoreUnknownInstances: true
|
ignoreUnknownInstances: true
|
||||||
Name: Workspace
|
Name: Workspace
|
||||||
Parent: id-2
|
Parent: id-2
|
||||||
Properties: {}
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
id-4:
|
id-4:
|
||||||
Children: []
|
Children: []
|
||||||
ClassName: ObjectValue
|
ClassName: ObjectValue
|
||||||
@@ -104,8 +106,12 @@ instances:
|
|||||||
Attributes:
|
Attributes:
|
||||||
Rojo_Target_PrimaryPart:
|
Rojo_Target_PrimaryPart:
|
||||||
String: model target
|
String: model target
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
PrimaryPart:
|
PrimaryPart:
|
||||||
Ref: id-7
|
Ref: id-7
|
||||||
|
Scale:
|
||||||
|
Float32: 1
|
||||||
id-9:
|
id-9:
|
||||||
Children:
|
Children:
|
||||||
- id-10
|
- id-10
|
||||||
@@ -116,5 +122,5 @@ instances:
|
|||||||
Name: ProjectTarget
|
Name: ProjectTarget
|
||||||
Parent: id-3
|
Parent: id-3
|
||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 0
|
messageCursor: 1
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ instances:
|
|||||||
ignoreUnknownInstances: true
|
ignoreUnknownInstances: true
|
||||||
Name: Workspace
|
Name: Workspace
|
||||||
Parent: id-2
|
Parent: id-2
|
||||||
Properties: {}
|
Properties:
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
id-4:
|
id-4:
|
||||||
Children: []
|
Children: []
|
||||||
ClassName: ObjectValue
|
ClassName: ObjectValue
|
||||||
@@ -104,6 +106,8 @@ instances:
|
|||||||
Attributes:
|
Attributes:
|
||||||
Rojo_Target_PrimaryPart:
|
Rojo_Target_PrimaryPart:
|
||||||
String: model target
|
String: model target
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
PrimaryPart:
|
PrimaryPart:
|
||||||
Ref: id-7
|
Ref: id-7
|
||||||
id-9:
|
id-9:
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
source: tests/tests/serve.rs
|
||||||
|
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
||||||
|
---
|
||||||
|
messageCursor: 1
|
||||||
|
messages:
|
||||||
|
- added: {}
|
||||||
|
removed: []
|
||||||
|
updated:
|
||||||
|
- changedClassName: ~
|
||||||
|
changedMetadata: ~
|
||||||
|
changedName: ~
|
||||||
|
changedProperties:
|
||||||
|
Scale:
|
||||||
|
Float32: 1
|
||||||
|
id: id-8
|
||||||
|
sessionId: id-1
|
||||||
@@ -10,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ messages:
|
|||||||
Attributes:
|
Attributes:
|
||||||
Rojo_Target_PrimaryPart:
|
Rojo_Target_PrimaryPart:
|
||||||
String: project target
|
String: project target
|
||||||
|
NeedsPivotMigration:
|
||||||
|
Bool: false
|
||||||
PrimaryPart:
|
PrimaryPart:
|
||||||
Ref: id-9
|
Ref: id-9
|
||||||
removed: []
|
removed: []
|
||||||
@@ -43,4 +45,3 @@ messages:
|
|||||||
PrimaryPart: ~
|
PrimaryPart: ~
|
||||||
id: id-8
|
id: id-8
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
gameId: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 265
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 281
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 297
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,4 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
assertion_line: 383
|
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
@@ -11,3 +10,4 @@ protocolVersion: 4
|
|||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
unexpectedPlaceIds: ~
|
||||||
|
|||||||
3
rojo-test/serve-tests/pivot_migration/Tool.model.json
Normal file
3
rojo-test/serve-tests/pivot_migration/Tool.model.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"className": "Tool"
|
||||||
|
}
|
||||||
14
rojo-test/serve-tests/pivot_migration/default.project.json
Normal file
14
rojo-test/serve-tests/pivot_migration/default.project.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "pivot_migration",
|
||||||
|
"tree": {
|
||||||
|
"$className": "DataModel",
|
||||||
|
"Workspace": {
|
||||||
|
"Model": {
|
||||||
|
"$className": "Model"
|
||||||
|
},
|
||||||
|
"Tool": {
|
||||||
|
"$path": "Tool.model.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
scripts/unit-test-plugin.sh
Normal file
2
scripts/unit-test-plugin.sh
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
rojo build plugin/test-place.project.json -o TestPlace.rbxl
|
||||||
|
run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl
|
||||||
1
scripts/watch-build-plugin.sh
Normal file
1
scripts/watch-build-plugin.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rojo build plugin.project.json --plugin Rojo.rbxm --watch
|
||||||
@@ -136,7 +136,7 @@ impl JobThreadContext {
|
|||||||
// created all at once.
|
// created all at once.
|
||||||
let mut current_path = path.as_path();
|
let mut current_path = path.as_path();
|
||||||
let affected_ids = loop {
|
let affected_ids = loop {
|
||||||
let ids = tree.get_ids_at_path(¤t_path);
|
let ids = tree.get_ids_at_path(current_path);
|
||||||
|
|
||||||
log::trace!("Path {} affects IDs {:?}", current_path.display(), ids);
|
log::trace!("Path {} affects IDs {:?}", current_path.display(), ids);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const UNKNOWN_PLUGIN_KIND_ERR: &str = "Could not detect what kind of file to bui
|
|||||||
/// Generates a model or place file from the Rojo project.
|
/// Generates a model or place file from the Rojo project.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct BuildCommand {
|
pub struct BuildCommand {
|
||||||
/// Path to the project to serve. Defaults to the current directory.
|
/// Path to the project to build. Defaults to the current directory.
|
||||||
#[clap(default_value = "")]
|
#[clap(default_value = "")]
|
||||||
pub project: PathBuf,
|
pub project: PathBuf,
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use clap::Parser;
|
|||||||
use fs_err::File;
|
use fs_err::File;
|
||||||
use memofs::Vfs;
|
use memofs::Vfs;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rbx_dom_weak::types::Ref;
|
use rbx_dom_weak::{types::Ref, Ustr};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ const PATH_STRIP_FAILED_ERR: &str = "Failed to create relative paths for project
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct SourcemapNode<'a> {
|
struct SourcemapNode<'a> {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
class_name: &'a str,
|
class_name: Ustr,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||||
file_paths: Vec<PathBuf>,
|
file_paths: Vec<PathBuf>,
|
||||||
@@ -67,7 +67,7 @@ impl SourcemapCommand {
|
|||||||
let vfs = Vfs::new_default();
|
let vfs = Vfs::new_default();
|
||||||
vfs.set_watch_enabled(self.watch);
|
vfs.set_watch_enabled(self.watch);
|
||||||
|
|
||||||
let session = ServeSession::new(vfs, &project_path)?;
|
let session = ServeSession::new(vfs, project_path)?;
|
||||||
let mut cursor = session.message_queue().cursor();
|
let mut cursor = session.message_queue().cursor();
|
||||||
|
|
||||||
let filter = if self.include_non_scripts {
|
let filter = if self.include_non_scripts {
|
||||||
@@ -113,7 +113,7 @@ fn filter_nothing(_instance: &InstanceWithMeta) -> bool {
|
|||||||
|
|
||||||
fn filter_non_scripts(instance: &InstanceWithMeta) -> bool {
|
fn filter_non_scripts(instance: &InstanceWithMeta) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
instance.class_name(),
|
instance.class_name().as_str(),
|
||||||
"Script" | "LocalScript" | "ModuleScript"
|
"Script" | "LocalScript" | "ModuleScript"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ trait FmtLua {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
struct DisplayLua<T>(T);
|
struct DisplayLua<T>(T);
|
||||||
|
|
||||||
impl<T> fmt::Display for DisplayLua<T>
|
impl<T> fmt::Display for DisplayLua<T>
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ impl<K: Hash + Eq, V: Eq> MultiMap<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> &[V]
|
pub fn get<Q>(&self, k: &Q) -> &[V]
|
||||||
where
|
where
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
Q: Hash + Eq,
|
Q: Hash + Eq + ?Sized,
|
||||||
{
|
{
|
||||||
self.inner.get(k).map(Vec::as_slice).unwrap_or(&[])
|
self.inner.get(k).map(Vec::as_slice).unwrap_or(&[])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,11 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use memofs::Vfs;
|
use memofs::Vfs;
|
||||||
|
use rbx_dom_weak::{Ustr, UstrMap};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{glob::Glob, resolution::UnresolvedValue, snapshot::SyncRule};
|
||||||
glob::Glob, resolution::UnresolvedValue, snapshot::SyncRule,
|
|
||||||
snapshot_middleware::default_sync_rules,
|
|
||||||
};
|
|
||||||
|
|
||||||
static PROJECT_FILENAME: &str = "default.project.json";
|
static PROJECT_FILENAME: &str = "default.project.json";
|
||||||
|
|
||||||
@@ -24,6 +22,13 @@ pub struct ProjectError(#[from] Error);
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
enum Error {
|
enum Error {
|
||||||
|
#[error(
|
||||||
|
"Rojo requires a project file, but no project file was found in path {}\n\
|
||||||
|
See https://rojo.space/docs/ for guides and documentation.",
|
||||||
|
.path.display()
|
||||||
|
)]
|
||||||
|
NoProjectFound { path: PathBuf },
|
||||||
|
|
||||||
#[error("The folder for the provided project cannot be used as a project name: {}\n\
|
#[error("The folder for the provided project cannot be used as a project name: {}\n\
|
||||||
Consider setting the `name` field on this project.", .path.display())]
|
Consider setting the `name` field on this project.", .path.display())]
|
||||||
FolderNameInvalid { path: PathBuf },
|
FolderNameInvalid { path: PathBuf },
|
||||||
@@ -51,6 +56,9 @@ enum Error {
|
|||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
|
#[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
|
||||||
|
schema: Option<String>,
|
||||||
|
|
||||||
/// The name of the top-level instance described by the project.
|
/// The name of the top-level instance described by the project.
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
|
||||||
@@ -71,6 +79,14 @@ pub struct Project {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub serve_place_ids: Option<HashSet<u64>>,
|
pub serve_place_ids: Option<HashSet<u64>>,
|
||||||
|
|
||||||
|
/// If specified, contains a set of place IDs that this project is
|
||||||
|
/// not compatible with when doing live sync.
|
||||||
|
///
|
||||||
|
/// This setting is intended to help prevent syncing a Rojo project into the
|
||||||
|
/// wrong Roblox place.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub blocked_place_ids: Option<HashSet<u64>>,
|
||||||
|
|
||||||
/// If specified, sets the current place's place ID when connecting to the
|
/// If specified, sets the current place's place ID when connecting to the
|
||||||
/// Rojo server from Roblox Studio.
|
/// Rojo server from Roblox Studio.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -219,7 +235,13 @@ impl Project {
|
|||||||
fuzzy_project_location: &Path,
|
fuzzy_project_location: &Path,
|
||||||
) -> Result<Option<Self>, ProjectError> {
|
) -> Result<Option<Self>, ProjectError> {
|
||||||
if let Some(project_path) = Self::locate(fuzzy_project_location) {
|
if let Some(project_path) = Self::locate(fuzzy_project_location) {
|
||||||
let contents = vfs.read(&project_path).map_err(Error::from)?;
|
let contents = vfs.read(&project_path).map_err(|e| match e.kind() {
|
||||||
|
io::ErrorKind::NotFound => Error::NoProjectFound {
|
||||||
|
path: project_path.to_path_buf(),
|
||||||
|
},
|
||||||
|
_ => e.into(),
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Some(Self::load_from_slice(&contents, project_path, None)?))
|
Ok(Some(Self::load_from_slice(&contents, project_path, None)?))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -233,7 +255,13 @@ impl Project {
|
|||||||
fallback_name: Option<&str>,
|
fallback_name: Option<&str>,
|
||||||
) -> Result<Self, ProjectError> {
|
) -> Result<Self, ProjectError> {
|
||||||
let project_path = project_file_location.to_path_buf();
|
let project_path = project_file_location.to_path_buf();
|
||||||
let contents = vfs.read(&project_path).map_err(Error::from)?;
|
let contents = vfs.read(&project_path).map_err(|e| match e.kind() {
|
||||||
|
io::ErrorKind::NotFound => Error::NoProjectFound {
|
||||||
|
path: project_path.to_path_buf(),
|
||||||
|
},
|
||||||
|
_ => e.into(),
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Self::load_from_slice(
|
Ok(Self::load_from_slice(
|
||||||
&contents,
|
&contents,
|
||||||
project_path,
|
project_path,
|
||||||
@@ -291,7 +319,7 @@ pub struct ProjectNode {
|
|||||||
/// `$className` CANNOT be set if `$path` is set and the instance described
|
/// `$className` CANNOT be set if `$path` is set and the instance described
|
||||||
/// by that path has a ClassName other than Folder.
|
/// by that path has a ClassName other than Folder.
|
||||||
#[serde(rename = "$className", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "$className", skip_serializing_if = "Option::is_none")]
|
||||||
pub class_name: Option<String>,
|
pub class_name: Option<Ustr>,
|
||||||
|
|
||||||
/// If set, defines an ID for the described Instance that can be used
|
/// If set, defines an ID for the described Instance that can be used
|
||||||
/// to refer to it for the purpose of referent properties.
|
/// to refer to it for the purpose of referent properties.
|
||||||
@@ -310,7 +338,7 @@ pub struct ProjectNode {
|
|||||||
default,
|
default,
|
||||||
skip_serializing_if = "HashMap::is_empty"
|
skip_serializing_if = "HashMap::is_empty"
|
||||||
)]
|
)]
|
||||||
pub properties: HashMap<String, UnresolvedValue>,
|
pub properties: UstrMap<UnresolvedValue>,
|
||||||
|
|
||||||
#[serde(
|
#[serde(
|
||||||
rename = "$attributes",
|
rename = "$attributes",
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::borrow::Borrow;
|
|||||||
|
|
||||||
use anyhow::{bail, format_err};
|
use anyhow::{bail, format_err};
|
||||||
use rbx_dom_weak::types::{
|
use rbx_dom_weak::types::{
|
||||||
Attributes, CFrame, Color3, Content, Enum, Font, MaterialColors, Matrix3, Tags, Variant,
|
Attributes, CFrame, Color3, Content, ContentId, Enum, Font, MaterialColors, Matrix3, Tags,
|
||||||
VariantType, Vector2, Vector3,
|
Variant, VariantType, Vector2, Vector3,
|
||||||
};
|
};
|
||||||
use rbx_reflection::{DataType, PropertyDescriptor};
|
use rbx_reflection::{DataType, PropertyDescriptor};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -116,6 +116,9 @@ impl AmbiguousValue {
|
|||||||
(VariantType::Content, AmbiguousValue::String(value)) => {
|
(VariantType::Content, AmbiguousValue::String(value)) => {
|
||||||
Ok(Content::from(value).into())
|
Ok(Content::from(value).into())
|
||||||
}
|
}
|
||||||
|
(VariantType::ContentId, AmbiguousValue::String(value)) => {
|
||||||
|
Ok(ContentId::from(value).into())
|
||||||
|
}
|
||||||
|
|
||||||
(VariantType::Vector2, AmbiguousValue::Array2(value)) => {
|
(VariantType::Vector2, AmbiguousValue::Array2(value)) => {
|
||||||
Ok(Vector2::new(value[0] as f32, value[1] as f32).into())
|
Ok(Vector2::new(value[0] as f32, value[1] as f32).into())
|
||||||
@@ -275,10 +278,20 @@ mod test {
|
|||||||
Variant::String("Hello!".into()),
|
Variant::String("Hello!".into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// String literals can also turn into Content
|
// String literals can also turn into ContentId
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve("Sky", "MoonTextureId", "\"rbxassetid://12345\""),
|
resolve("Sky", "MoonTextureId", "\"rbxassetid://12345\""),
|
||||||
Variant::Content("rbxassetid://12345".into()),
|
Variant::ContentId("rbxassetid://12345".into()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// String literals can turn into Content!
|
||||||
|
assert_eq!(
|
||||||
|
resolve(
|
||||||
|
"MeshPart",
|
||||||
|
"MeshContent",
|
||||||
|
"\"rbxasset://totally-a-real-uri.tiff\""
|
||||||
|
),
|
||||||
|
Variant::Content("rbxasset://totally-a-real-uri.tiff".into())
|
||||||
);
|
);
|
||||||
|
|
||||||
// What about BinaryString values? For forward-compatibility reasons, we
|
// What about BinaryString values? For forward-compatibility reasons, we
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{
|
|||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
io,
|
io,
|
||||||
net::IpAddr,
|
net::IpAddr,
|
||||||
path::{Path, PathBuf},
|
path::Path,
|
||||||
sync::{Arc, Mutex, MutexGuard},
|
sync::{Arc, Mutex, MutexGuard},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
@@ -109,14 +109,7 @@ impl ServeSession {
|
|||||||
|
|
||||||
log::debug!("Loading project file from {}", project_path.display());
|
log::debug!("Loading project file from {}", project_path.display());
|
||||||
|
|
||||||
let root_project = match Project::load_exact(&vfs, &project_path, None) {
|
let root_project = Project::load_exact(&vfs, &project_path, None)?;
|
||||||
Ok(project) => project,
|
|
||||||
Err(_) => {
|
|
||||||
return Err(ServeSessionError::NoProjectFound {
|
|
||||||
path: project_path.to_path_buf(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut tree = RojoTree::new(InstanceSnapshot::new());
|
let mut tree = RojoTree::new(InstanceSnapshot::new());
|
||||||
|
|
||||||
@@ -215,6 +208,10 @@ impl ServeSession {
|
|||||||
self.root_project.serve_place_ids.as_ref()
|
self.root_project.serve_place_ids.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn blocked_place_ids(&self) -> Option<&HashSet<u64>> {
|
||||||
|
self.root_project.blocked_place_ids.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serve_address(&self) -> Option<IpAddr> {
|
pub fn serve_address(&self) -> Option<IpAddr> {
|
||||||
self.root_project.serve_address
|
self.root_project.serve_address
|
||||||
}
|
}
|
||||||
@@ -226,13 +223,6 @@ impl ServeSession {
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ServeSessionError {
|
pub enum ServeSessionError {
|
||||||
#[error(
|
|
||||||
"Rojo requires a project file, but no project file was found in path {}\n\
|
|
||||||
See https://rojo.space/docs/ for guides and documentation.",
|
|
||||||
.path.display()
|
|
||||||
)]
|
|
||||||
NoProjectFound { path: PathBuf },
|
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io {
|
Io {
|
||||||
#[from]
|
#[from]
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
//! Defines the structure of an instance snapshot.
|
//! Defines the structure of an instance snapshot.
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rbx_dom_weak::{
|
use rbx_dom_weak::{
|
||||||
types::{Ref, Variant},
|
types::{Ref, Variant},
|
||||||
Instance, WeakDom,
|
ustr, AHashMap, HashMapExt as _, Instance, Ustr, UstrMap, WeakDom,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -27,10 +27,10 @@ pub struct InstanceSnapshot {
|
|||||||
pub name: Cow<'static, str>,
|
pub name: Cow<'static, str>,
|
||||||
|
|
||||||
/// Corresponds to the ClassName property of the instance.
|
/// Corresponds to the ClassName property of the instance.
|
||||||
pub class_name: Cow<'static, str>,
|
pub class_name: Ustr,
|
||||||
|
|
||||||
/// All other properties of the instance, weakly-typed.
|
/// All other properties of the instance, weakly-typed.
|
||||||
pub properties: HashMap<String, Variant>,
|
pub properties: UstrMap<Variant>,
|
||||||
|
|
||||||
/// The children of the instance represented as more snapshots.
|
/// The children of the instance represented as more snapshots.
|
||||||
///
|
///
|
||||||
@@ -44,8 +44,8 @@ impl InstanceSnapshot {
|
|||||||
snapshot_id: Ref::none(),
|
snapshot_id: Ref::none(),
|
||||||
metadata: InstanceMetadata::default(),
|
metadata: InstanceMetadata::default(),
|
||||||
name: Cow::Borrowed("DEFAULT"),
|
name: Cow::Borrowed("DEFAULT"),
|
||||||
class_name: Cow::Borrowed("DEFAULT"),
|
class_name: ustr("DEFAULT"),
|
||||||
properties: HashMap::new(),
|
properties: UstrMap::new(),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,23 +57,23 @@ impl InstanceSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_name(self, class_name: impl Into<String>) -> Self {
|
pub fn class_name<S: Into<Ustr>>(self, class_name: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
class_name: Cow::Owned(class_name.into()),
|
class_name: class_name.into(),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn property<K, V>(mut self, key: K, value: V) -> Self
|
pub fn property<K, V>(mut self, key: K, value: V) -> Self
|
||||||
where
|
where
|
||||||
K: Into<String>,
|
K: Into<Ustr>,
|
||||||
V: Into<Variant>,
|
V: Into<Variant>,
|
||||||
{
|
{
|
||||||
self.properties.insert(key.into(), value.into());
|
self.properties.insert(key.into(), value.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn properties(self, properties: impl Into<HashMap<String, Variant>>) -> Self {
|
pub fn properties(self, properties: impl Into<UstrMap<Variant>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
properties: properties.into(),
|
properties: properties.into(),
|
||||||
..self
|
..self
|
||||||
@@ -107,7 +107,7 @@ impl InstanceSnapshot {
|
|||||||
Self::from_raw_tree(&mut raw_tree, id)
|
Self::from_raw_tree(&mut raw_tree, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_raw_tree(raw_tree: &mut HashMap<Ref, Instance>, id: Ref) -> Self {
|
fn from_raw_tree(raw_tree: &mut AHashMap<Ref, Instance>, id: Ref) -> Self {
|
||||||
let instance = raw_tree
|
let instance = raw_tree
|
||||||
.remove(&id)
|
.remove(&id)
|
||||||
.expect("instance did not exist in tree");
|
.expect("instance did not exist in tree");
|
||||||
@@ -122,7 +122,7 @@ impl InstanceSnapshot {
|
|||||||
snapshot_id: id,
|
snapshot_id: id,
|
||||||
metadata: InstanceMetadata::default(),
|
metadata: InstanceMetadata::default(),
|
||||||
name: Cow::Owned(instance.name),
|
name: Cow::Owned(instance.name),
|
||||||
class_name: Cow::Owned(instance.class),
|
class_name: instance.class,
|
||||||
properties: instance.properties,
|
properties: instance.properties,
|
||||||
children,
|
children,
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user