mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-22 21:55:15 +00:00
Compare commits
3 Commits
v7.0.0-alp
...
v6.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0599b50235 | ||
|
|
21f7ef6186 | ||
|
|
de6470bb45 |
43
CHANGELOG.md
43
CHANGELOG.md
@@ -2,49 +2,12 @@
|
|||||||
|
|
||||||
## Unreleased Changes
|
## Unreleased Changes
|
||||||
|
|
||||||
## [7.0.0-alpha.4][7.0.0-alpha.4] (May 5, 2021)
|
## [6.1.0][6.1.0] (April 12, 2021)
|
||||||
* Added the `gameId` and `placeId` optional properties to project files.
|
* Updated dependencies, fixing OptionalCoordinateFrame-related issues.
|
||||||
* When connecting from the Rojo Roblox Studio plugin, Rojo will set the game and place ID of the current place to these values, if set.
|
|
||||||
* This is equivalent to running `game:SetUniverseId(...)` and `game:SetPlaceId(...)` from the command bar in Studio.
|
|
||||||
* Added "EXPERIMENTAL!" label to two-way sync toggle in Rojo's Roblox Studio plugin.
|
|
||||||
* Fixed `Name` and `Parent` properties being allowed in Rojo projects. ([#413][pr-413])
|
|
||||||
* Fixed "Open Scripts Externally" feature crashing Studio. ([#369][issue-369])
|
|
||||||
* Empty `.model.json` files will no longer cause errors. ([#420][pr-420])
|
|
||||||
* When specifying `$path` on a service, Rojo now keeps the correct class name. ([#331][issue-331])
|
|
||||||
* Improved error messages for misconfigured projects.
|
|
||||||
|
|
||||||
[issue-331]: https://github.com/rojo-rbx/rojo/issues/331
|
|
||||||
[issue-369]: https://github.com/rojo-rbx/rojo/issues/369
|
|
||||||
[pr-420]: https://github.com/rojo-rbx/rojo/pull/420
|
|
||||||
[pr-413]: https://github.com/rojo-rbx/rojo/pull/413
|
|
||||||
[7.0.0-alpha.4]: https://github.com/rojo-rbx/rojo/releases/tag/v7.0.0-alpha.4
|
|
||||||
|
|
||||||
## [7.0.0-alpha.3][7.0.0-alpha.3] (February 19, 2021)
|
|
||||||
* Updated dependencies, fixing `OptionalCoordinateFrame`-related issues.
|
|
||||||
* Added `--address` flag to `rojo serve` to allow for external connections. ([#403][pr-403])
|
* Added `--address` flag to `rojo serve` to allow for external connections. ([#403][pr-403])
|
||||||
|
|
||||||
[pr-403]: https://github.com/rojo-rbx/rojo/pull/403
|
[pr-403]: https://github.com/rojo-rbx/rojo/pull/403
|
||||||
[7.0.0-alpha.3]: https://github.com/rojo-rbx/rojo/releases/tag/v7.0.0-alpha.3
|
[6.1.0]: https://github.com/rojo-rbx/rojo/releases/tag/v6.1.0
|
||||||
|
|
||||||
## [7.0.0-alpha.2][7.0.0-alpha.2] (February 19, 2021)
|
|
||||||
* Fixed incorrect protocol version between the client and server.
|
|
||||||
|
|
||||||
[7.0.0-alpha.2]: https://github.com/rojo-rbx/rojo/releases/tag/v7.0.0-alpha.2
|
|
||||||
|
|
||||||
## [7.0.0-alpha.1][7.0.0-alpha.1] (February 18, 2021)
|
|
||||||
This release includes a brand new implementation of the Roblox DOM. It brings performance improvements, much better support for `rbxl` and `rbxm` files, and a better internal API.
|
|
||||||
|
|
||||||
* Added support for all remaining property types.
|
|
||||||
* Added support for the entire Roblox binary model format.
|
|
||||||
* Changed `rojo upload` to upload binary places and models instead of XML.
|
|
||||||
* This should make using `rojo upload` much more feasible for large places.
|
|
||||||
* **Breaking**: Changed format of some types of values in `project.json`, `model.json`, and `meta.json` files.
|
|
||||||
* This should impact few projects. See [this file][allValues.json] for new examples of each property type.
|
|
||||||
|
|
||||||
Formatting of types will change more before the stable release of Rojo 7. We're hoping to use this opportunity to normalize some of the case inconsistency introduced in Rojo 0.5.
|
|
||||||
|
|
||||||
[7.0.0-alpha.1]: https://github.com/rojo-rbx/rojo/releases/tag/v7.0.0-alpha.1
|
|
||||||
[allValues.json]: https://github.com/rojo-rbx/rojo/blob/f4a790eb50b74e482000bad1dcfe22533992fb20/plugin/rbx_dom_lua/src/allValues.json
|
|
||||||
|
|
||||||
## [6.0.2](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.2) (February 9, 2021)
|
## [6.0.2](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.2) (February 9, 2021)
|
||||||
* Fixed `rojo upload` to handle CSRF challenges.
|
* Fixed `rojo upload` to handle CSRF challenges.
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ The Rojo release process is pretty manual right now. If you need to do it, here'
|
|||||||
6. Tag the commit with the version from `Cargo.toml` prepended with a v, like `v0.4.13`
|
6. Tag the commit with the version from `Cargo.toml` prepended with a v, like `v0.4.13`
|
||||||
7. Publish the CLI
|
7. Publish the CLI
|
||||||
* `cargo publish`
|
* `cargo publish`
|
||||||
8. Publish the Plugin
|
8. Build and upload the plugin
|
||||||
* `rojo publish plugin --asset_id 6415005344`
|
|
||||||
* `rojo build plugin -o Rojo.rbxm`
|
* `rojo build plugin -o Rojo.rbxm`
|
||||||
|
* Upload `Rojo.rbxm` to Roblox.com, keep it for later
|
||||||
9. Push commits and tags
|
9. Push commits and tags
|
||||||
* `git push && git push --tags`
|
* `git push && git push --tags`
|
||||||
10. Copy GitHub release content from previous release
|
10. Copy GitHub release content from previous release
|
||||||
|
|||||||
412
Cargo.lock
generated
412
Cargo.lock
generated
@@ -2,9 +2,9 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.15.1"
|
version = "0.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a"
|
checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gimli",
|
"gimli",
|
||||||
]
|
]
|
||||||
@@ -17,9 +17,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -76,12 +76,11 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.59"
|
version = "0.3.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
|
checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cc",
|
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
@@ -105,11 +104,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "base64"
|
||||||
version = "1.3.3"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -120,18 +126,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake2b_simd"
|
||||||
version = "0.1.5"
|
version = "0.5.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46080006c1505f12f64dd2a09264b343381ed3190fa02c8005d5d662ac571c63"
|
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cc",
|
|
||||||
"cfg-if 0.1.10",
|
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
"crypto-mac",
|
|
||||||
"digest",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -157,9 +159,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "0.2.16"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
|
checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -181,9 +183,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.4.3"
|
version = "1.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
@@ -198,9 +200,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cast"
|
name = "cast"
|
||||||
version = "0.2.5"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc38c385bfd7e444464011bb24820f40dd1c76bcdfa1b78611cb7c2e5cafab75"
|
checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
@@ -367,12 +369,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.1"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils 0.8.4",
|
"crossbeam-utils 0.8.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -393,8 +395,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-epoch 0.9.4",
|
"crossbeam-epoch 0.9.3",
|
||||||
"crossbeam-utils 0.8.4",
|
"crossbeam-utils 0.8.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -414,12 +416,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "crossbeam-epoch"
|
||||||
version = "0.9.4"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
|
checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils 0.8.4",
|
"crossbeam-utils 0.8.3",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"memoffset 0.6.3",
|
"memoffset 0.6.3",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
@@ -449,25 +451,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278"
|
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.1",
|
"autocfg 1.0.1",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-mac"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csv"
|
name = "csv"
|
||||||
version = "1.1.6"
|
version = "1.1.6"
|
||||||
@@ -527,15 +519,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-sys"
|
name = "dirs-sys"
|
||||||
version = "0.3.6"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
|
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
@@ -612,7 +610,7 @@ checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.2.8",
|
"redox_syscall 0.2.5",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -661,9 +659,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs-err"
|
name = "fs-err"
|
||||||
version = "2.6.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ebd3504ad6116843b8375ad70df74e7bfe83cac77a1f3fe73200c844d43bfe0"
|
checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsevent"
|
name = "fsevent"
|
||||||
@@ -755,9 +753,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.24.0"
|
version = "0.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
|
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
@@ -851,9 +849,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.4.1"
|
version = "1.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
|
checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
@@ -920,9 +918,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.3"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matches",
|
"matches",
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
@@ -1017,9 +1015,9 @@ checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.51"
|
version = "0.3.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
|
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -1048,9 +1046,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.94"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
@@ -1115,10 +1113,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "md5"
|
||||||
version = "2.4.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
@@ -1259,9 +1263,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "4.0.17"
|
version = "4.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
|
checksum = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"filetime",
|
"filetime",
|
||||||
@@ -1296,9 +1300,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.24.0"
|
version = "0.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
|
checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
@@ -1329,9 +1333,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.34"
|
version = "0.10.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8"
|
checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
@@ -1343,15 +1347,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.4"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.63"
|
version = "0.9.61"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98"
|
checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.1",
|
"autocfg 1.0.1",
|
||||||
"cc",
|
"cc",
|
||||||
@@ -1572,7 +1576,7 @@ version = "1.0.26"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.2.2",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1581,8 +1585,8 @@ version = "1.5.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f"
|
checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"idna 0.2.3",
|
"idna 0.2.2",
|
||||||
"url 2.2.2",
|
"url 2.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1628,19 +1632,6 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.1.16",
|
|
||||||
"libc",
|
|
||||||
"rand_chacha 0.2.2",
|
|
||||||
"rand_core 0.5.1",
|
|
||||||
"rand_hc 0.2.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
@@ -1663,16 +1654,6 @@ dependencies = [
|
|||||||
"rand_core 0.3.1",
|
"rand_core 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core 0.5.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -1698,15 +1679,6 @@ version = "0.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.1.16",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -1725,15 +1697,6 @@ dependencies = [
|
|||||||
"rand_core 0.3.1",
|
"rand_core 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_hc"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.5.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_hc"
|
name = "rand_hc"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -1814,84 +1777,64 @@ version = "1.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel 0.5.1",
|
"crossbeam-channel 0.5.0",
|
||||||
"crossbeam-deque 0.8.0",
|
"crossbeam-deque 0.8.0",
|
||||||
"crossbeam-utils 0.8.4",
|
"crossbeam-utils 0.8.3",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_binary"
|
name = "rbx_binary"
|
||||||
version = "0.6.0-alpha.5"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d7e87ab0f16f2a911b38d3761bf694743d1ea75638becd9ff355b462d33bbfa"
|
checksum = "5b1c0c2b715bb763be1e27e5118e1f1ce0381f6c396a9cc8dd2c4b818cfa247d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
"log",
|
"log",
|
||||||
"lz4",
|
"lz4",
|
||||||
"rbx_dom_weak",
|
"rbx_dom_weak",
|
||||||
"rbx_reflection",
|
"rbx_reflection",
|
||||||
"rbx_reflection_database",
|
"snafu",
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_dom_weak"
|
name = "rbx_dom_weak"
|
||||||
version = "2.0.0-alpha.1"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ffa16d4ae69867cbe305d740790900193147ce5a904fc583f88dbfc7de43a95"
|
checksum = "978b65ce742f3cb38c0b64ca48601a5590e6be9a14d12025b9cba2fe553b78c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rbx_types",
|
"base64 0.11.0",
|
||||||
|
"lazy_static",
|
||||||
|
"md5",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_repr",
|
||||||
|
"uuid 0.8.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_reflection"
|
name = "rbx_reflection"
|
||||||
version = "4.0.0-alpha.1"
|
version = "3.3.454"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c43632d239190aad5b9406a6f0df2233ae3b46489957dd6d11c4d6daa9046c5"
|
checksum = "e9ccdde2a675eb13a8ecfe1f60879bf11ab29e9a671459d833929298873eedc4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rbx_types",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rbx_reflection_database"
|
|
||||||
version = "0.1.1+roblox-478"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "027b05433fe77e2608b95524d61bdd5db51ec93a80f20e0b2ef1bcf8a43894ca"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"rbx_reflection",
|
|
||||||
"rmp-serde",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rbx_types"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5ee26785b8236954e96d907ee0226a4c0761ebb5855ed115cc363979bd503331"
|
|
||||||
dependencies = [
|
|
||||||
"base64 0.11.0",
|
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"blake3",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"rand 0.7.3",
|
"rbx_dom_weak",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbx_xml"
|
name = "rbx_xml"
|
||||||
version = "0.12.0-alpha.4"
|
version = "0.11.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86e2277d678ea30609e6f383a8f34eabab7bb2f9d62144cbe400d179acea2d47"
|
checksum = "cf4c21ca838512b3629639c3be776f8550495dc53901c94e7771e71d2f09fa7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.11.0",
|
"base64 0.11.0",
|
||||||
"log",
|
"log",
|
||||||
"rbx_dom_weak",
|
"rbx_dom_weak",
|
||||||
"rbx_reflection",
|
"rbx_reflection",
|
||||||
"rbx_reflection_database",
|
|
||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1912,28 +1855,29 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.8"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.0"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.2",
|
"getrandom 0.1.16",
|
||||||
"redox_syscall 0.2.8",
|
"redox_syscall 0.1.57",
|
||||||
|
"rust-argon2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.4"
|
version = "1.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -1951,9 +1895,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.25"
|
version = "0.6.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
@@ -2035,27 +1979,6 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rmp"
|
|
||||||
version = "0.8.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rmp-serde"
|
|
||||||
version = "0.14.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ce7d70c926fe472aed493b902010bccc17fa9f7284145cb8772fd22fdb052d8"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"rmp",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roblox_install"
|
name = "roblox_install"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -2068,7 +1991,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "7.0.0-alpha.4"
|
version = "6.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
@@ -2095,7 +2018,6 @@ dependencies = [
|
|||||||
"rbx_binary",
|
"rbx_binary",
|
||||||
"rbx_dom_weak",
|
"rbx_dom_weak",
|
||||||
"rbx_reflection",
|
"rbx_reflection",
|
||||||
"rbx_reflection_database",
|
|
||||||
"rbx_xml",
|
"rbx_xml",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@@ -2125,10 +2047,22 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rust-argon2"
|
||||||
version = "0.1.19"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
|
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.0",
|
||||||
|
"blake2b_simd",
|
||||||
|
"constant_time_eq",
|
||||||
|
"crossbeam-utils 0.8.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
@@ -2210,9 +2144,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.126"
|
version = "1.0.125"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@@ -2229,9 +2163,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.126"
|
version = "1.0.125"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.26",
|
"proc-macro2 1.0.26",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
@@ -2249,6 +2183,17 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_repr"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.26",
|
||||||
|
"quote 1.0.9",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.5.5"
|
version = "0.5.5"
|
||||||
@@ -2293,9 +2238,9 @@ checksum = "1ad1d488a557b235fc46dae55512ffbfc429d2482b08b4d9435ab07384ca8aec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.3"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
@@ -2306,6 +2251,27 @@ dependencies = [
|
|||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snafu"
|
||||||
|
version = "0.6.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7"
|
||||||
|
dependencies = [
|
||||||
|
"doc-comment",
|
||||||
|
"snafu-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snafu-derive"
|
||||||
|
version = "0.6.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.26",
|
||||||
|
"quote 1.0.9",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "snax"
|
name = "snax"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -2354,21 +2320,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtle"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.72"
|
version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.26",
|
"proc-macro2 1.0.26",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"unicode-xid 0.2.2",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2380,7 +2340,7 @@ dependencies = [
|
|||||||
"proc-macro2 1.0.26",
|
"proc-macro2 1.0.26",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn",
|
"syn",
|
||||||
"unicode-xid 0.2.2",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2392,7 +2352,7 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"rand 0.8.3",
|
"rand 0.8.3",
|
||||||
"redox_syscall 0.2.8",
|
"redox_syscall 0.2.5",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
@@ -2747,9 +2707,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
@@ -2764,12 +2724,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.2.2"
|
version = "2.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna 0.2.3",
|
"idna 0.2.2",
|
||||||
"matches",
|
"matches",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
]
|
]
|
||||||
@@ -2795,9 +2755,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.12"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d"
|
checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
@@ -2847,9 +2807,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.74"
|
version = "0.2.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@@ -2857,9 +2817,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.74"
|
version = "0.2.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -2872,9 +2832,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.74"
|
version = "0.2.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -2882,9 +2842,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.74"
|
version = "0.2.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.26",
|
"proc-macro2 1.0.26",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
@@ -2895,15 +2855,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.74"
|
version = "0.2.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.51"
|
version = "0.3.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
|
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|||||||
19
Cargo.toml
19
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "7.0.0-alpha.4"
|
version = "6.1.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"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
@@ -47,19 +47,6 @@ harness = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
memofs = { version = "0.1.2", path = "memofs" }
|
memofs = { version = "0.1.2", path = "memofs" }
|
||||||
|
|
||||||
# These dependencies can be uncommented when working on rbx-dom simultaneously
|
|
||||||
# rbx_binary = { path = "../rbx-dom/rbx_binary" }
|
|
||||||
# rbx_dom_weak = { path = "../rbx-dom/rbx_dom_weak" }
|
|
||||||
# rbx_reflection = { path = "../rbx-dom/rbx_reflection" }
|
|
||||||
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
|
|
||||||
# rbx_xml = { path = "../rbx-dom/rbx_xml" }
|
|
||||||
|
|
||||||
rbx_binary = "0.6.0-alpha.1"
|
|
||||||
rbx_dom_weak = "2.0.0-alpha.1"
|
|
||||||
rbx_reflection = "4.0.0-alpha.1"
|
|
||||||
rbx_reflection_database = "0.1.0"
|
|
||||||
rbx_xml = "0.12.0-alpha.1"
|
|
||||||
|
|
||||||
anyhow = "1.0.27"
|
anyhow = "1.0.27"
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
@@ -77,6 +64,10 @@ log = "0.4.8"
|
|||||||
maplit = "1.0.1"
|
maplit = "1.0.1"
|
||||||
notify = "4.0.14"
|
notify = "4.0.14"
|
||||||
opener = "0.4.1"
|
opener = "0.4.1"
|
||||||
|
rbx_binary = "0.5.0"
|
||||||
|
rbx_dom_weak = "1.10.1"
|
||||||
|
rbx_reflection = "3.3.408"
|
||||||
|
rbx_xml = "0.11.3"
|
||||||
regex = "1.3.1"
|
regex = "1.3.1"
|
||||||
reqwest = "0.9.20"
|
reqwest = "0.9.20"
|
||||||
ritz = "0.1.0"
|
ritz = "0.1.0"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[tools]
|
[tools]
|
||||||
rojo = { source = "rojo-rbx/rojo", version = "6.1.0" }
|
rojo = { source = "rojo-rbx/rojo", version = "6.0.0-rc.3" }
|
||||||
run-in-roblox = { source = "rojo-rbx/run-in-roblox", version = "0.3.0" }
|
run-in-roblox = { source = "rojo-rbx/run-in-roblox", version = "0.3.0" }
|
||||||
|
|||||||
44
plugin/rbx_dom_lua/.luacheckrc
Normal file
44
plugin/rbx_dom_lua/.luacheckrc
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
stds.roblox = {
|
||||||
|
read_globals = {
|
||||||
|
game = {
|
||||||
|
other_fields = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Roblox globals
|
||||||
|
"script",
|
||||||
|
|
||||||
|
-- Extra functions
|
||||||
|
"tick", "warn",
|
||||||
|
"wait", "typeof",
|
||||||
|
|
||||||
|
-- Types
|
||||||
|
"CFrame",
|
||||||
|
"Color3",
|
||||||
|
"Enum",
|
||||||
|
"Instance",
|
||||||
|
"NumberRange",
|
||||||
|
"Rect",
|
||||||
|
"UDim", "UDim2",
|
||||||
|
"Vector2", "Vector3",
|
||||||
|
"Vector2int16", "Vector3int16",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stds.testez = {
|
||||||
|
read_globals = {
|
||||||
|
"describe",
|
||||||
|
"it", "itFOCUS", "itSKIP",
|
||||||
|
"FOCUS", "SKIP", "HACK_NO_XPCALL",
|
||||||
|
"expect",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore = {
|
||||||
|
"212", -- unused arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
std = "lua51+roblox"
|
||||||
|
|
||||||
|
files["**/*.spec.lua"] = {
|
||||||
|
std = "+testez",
|
||||||
|
}
|
||||||
@@ -1,456 +0,0 @@
|
|||||||
local base64 = require(script.Parent.base64)
|
|
||||||
|
|
||||||
local function identity(...)
|
|
||||||
return ...
|
|
||||||
end
|
|
||||||
|
|
||||||
local function unpackDecoder(f)
|
|
||||||
return function(value)
|
|
||||||
return f(unpack(value))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function serializeFloat(value)
|
|
||||||
-- TODO: Figure out a better way to serialize infinity and NaN, neither of
|
|
||||||
-- which fit into JSON.
|
|
||||||
if value == math.huge or value == -math.huge then
|
|
||||||
return 999999999 * math.sign(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
return value
|
|
||||||
end
|
|
||||||
|
|
||||||
local ALL_AXES = {"X", "Y", "Z"}
|
|
||||||
local ALL_FACES = {"Right", "Top", "Back", "Left", "Bottom", "Front"}
|
|
||||||
|
|
||||||
local types
|
|
||||||
types = {
|
|
||||||
Axes = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
local axes = {}
|
|
||||||
|
|
||||||
for index, axisName in ipairs(pod) do
|
|
||||||
axes[index] = Enum.Axis[axisName]
|
|
||||||
end
|
|
||||||
|
|
||||||
return Axes.new(unpack(axes))
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
local json = {}
|
|
||||||
|
|
||||||
for _, axis in ipairs(ALL_AXES) do
|
|
||||||
if roblox[axis] then
|
|
||||||
table.insert(json, axis)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return json
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
BinaryString = {
|
|
||||||
fromPod = base64.decode,
|
|
||||||
toPod = base64.encode,
|
|
||||||
},
|
|
||||||
|
|
||||||
Bool = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = identity,
|
|
||||||
},
|
|
||||||
|
|
||||||
BrickColor = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
return BrickColor.new(pod)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return roblox.Number
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
CFrame = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
local pos = pod.Position
|
|
||||||
local orient = pod.Orientation
|
|
||||||
|
|
||||||
return CFrame.new(
|
|
||||||
pos[1], pos[2], pos[3],
|
|
||||||
orient[1][1], orient[1][2], orient[1][3],
|
|
||||||
orient[2][1], orient[2][2], orient[2][3],
|
|
||||||
orient[3][1], orient[3][2], orient[3][3]
|
|
||||||
)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
local x, y, z,
|
|
||||||
r00, r01, r02,
|
|
||||||
r10, r11, r12,
|
|
||||||
r20, r21, r22 = roblox:GetComponents()
|
|
||||||
|
|
||||||
return {
|
|
||||||
Position = {x, y, z},
|
|
||||||
Orientation = {
|
|
||||||
{r00, r01, r02},
|
|
||||||
{r10, r11, r12},
|
|
||||||
{r20, r21, r22},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Color3 = {
|
|
||||||
fromPod = unpackDecoder(Color3.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {roblox.r, roblox.g, roblox.b}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Color3uint8 = {
|
|
||||||
fromPod = unpackDecoder(Color3.fromRGB),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
math.round(roblox.R * 255),
|
|
||||||
math.round(roblox.G * 255),
|
|
||||||
math.round(roblox.B * 255),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
ColorSequence = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
local keypoints = {}
|
|
||||||
|
|
||||||
for index, keypoint in ipairs(pod.Keypoints) do
|
|
||||||
keypoints[index] = ColorSequenceKeypoint.new(
|
|
||||||
keypoint.Time,
|
|
||||||
types.Color3.fromPod(keypoint.Color)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
return ColorSequence.new(keypoints)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
local keypoints = {}
|
|
||||||
|
|
||||||
for index, keypoint in ipairs(roblox.Keypoints) do
|
|
||||||
keypoints[index] = {
|
|
||||||
Time = keypoint.Time,
|
|
||||||
Color = types.Color3.toPod(keypoint.Value),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
Keypoints = keypoints,
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Content = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = identity,
|
|
||||||
},
|
|
||||||
|
|
||||||
Enum = {
|
|
||||||
fromPod = identity,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
-- FIXME: More robust handling of enums
|
|
||||||
if typeof(roblox) == "number" then
|
|
||||||
return roblox
|
|
||||||
else
|
|
||||||
return roblox.Value
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Faces = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
local faces = {}
|
|
||||||
|
|
||||||
for index, faceName in ipairs(pod) do
|
|
||||||
faces[index] = Enum.NormalId[faceName]
|
|
||||||
end
|
|
||||||
|
|
||||||
return Faces.new(unpack(faces))
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
local pod = {}
|
|
||||||
|
|
||||||
for _, face in ipairs(ALL_FACES) do
|
|
||||||
if roblox[face] then
|
|
||||||
table.insert(pod, face)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return pod
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Float32 = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = serializeFloat,
|
|
||||||
},
|
|
||||||
|
|
||||||
Float64 = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = serializeFloat,
|
|
||||||
},
|
|
||||||
|
|
||||||
Int32 = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = identity,
|
|
||||||
},
|
|
||||||
|
|
||||||
Int64 = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = identity,
|
|
||||||
},
|
|
||||||
|
|
||||||
NumberRange = {
|
|
||||||
fromPod = unpackDecoder(NumberRange.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {roblox.Min, roblox.Max}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
NumberSequence = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
local keypoints = {}
|
|
||||||
|
|
||||||
for index, keypoint in ipairs(pod.Keypoints) do
|
|
||||||
keypoints[index] = NumberSequenceKeypoint.new(
|
|
||||||
keypoint.Time,
|
|
||||||
keypoint.Value,
|
|
||||||
keypoint.Envelope
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
return NumberSequence.new(keypoints)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
local keypoints = {}
|
|
||||||
|
|
||||||
for index, keypoint in ipairs(roblox.Keypoints) do
|
|
||||||
keypoints[index] = {
|
|
||||||
Time = keypoint.Time,
|
|
||||||
Value = keypoint.Value,
|
|
||||||
Envelope = keypoint.Envelope,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
Keypoints = keypoints,
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
PhysicalProperties = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
if pod == "Default" then
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
return PhysicalProperties.new(
|
|
||||||
pod.Density,
|
|
||||||
pod.Friction,
|
|
||||||
pod.Elasticity,
|
|
||||||
pod.FrictionWeight,
|
|
||||||
pod.ElasticityWeight
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
if roblox == nil then
|
|
||||||
return "Default"
|
|
||||||
else
|
|
||||||
return {
|
|
||||||
Density = roblox.Density,
|
|
||||||
Friction = roblox.Friction,
|
|
||||||
Elasticity = roblox.Elasticity,
|
|
||||||
FrictionWeight = roblox.FrictionWeight,
|
|
||||||
ElasticityWeight = roblox.ElasticityWeight,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Ray = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
return Ray.new(
|
|
||||||
types.Vector3.fromPod(pod.Origin),
|
|
||||||
types.Vector3.fromPod(pod.Direction)
|
|
||||||
)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
Origin = types.Vector3.toPod(roblox.Origin),
|
|
||||||
Direction = types.Vector3.toPod(roblox.Direction),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Rect = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
return Rect.new(
|
|
||||||
types.Vector2.fromPod(pod[1]),
|
|
||||||
types.Vector2.fromPod(pod[2])
|
|
||||||
)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
types.Vector2.toPod(roblox.Min),
|
|
||||||
types.Vector2.toPod(roblox.Max),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Ref = {
|
|
||||||
fromPod = function(_pod)
|
|
||||||
error("Ref cannot be decoded on its own")
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(_roblox)
|
|
||||||
error("Ref can not be encoded on its own")
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Region3 = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
error("Region3 is not implemented")
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
error("Region3 is not implemented")
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Region3int16 = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
return Region3int16.new(
|
|
||||||
types.Vector3int16.fromPod(pod[1]),
|
|
||||||
types.Vector3int16.fromPod(pod[2])
|
|
||||||
)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
types.Vector3int16.toPod(roblox.Min),
|
|
||||||
types.Vector3int16.toPod(roblox.Max),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
SharedString = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
error("SharedString is not supported")
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
error("SharedString is not supported")
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
String = {
|
|
||||||
fromPod = identity,
|
|
||||||
toPod = identity,
|
|
||||||
},
|
|
||||||
|
|
||||||
UDim = {
|
|
||||||
fromPod = unpackDecoder(UDim.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {roblox.Scale, roblox.Offset}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
UDim2 = {
|
|
||||||
fromPod = function(pod)
|
|
||||||
return UDim2.new(
|
|
||||||
types.UDim.fromPod(pod[1]),
|
|
||||||
types.UDim.fromPod(pod[2])
|
|
||||||
)
|
|
||||||
end,
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
types.UDim.toPod(roblox.X),
|
|
||||||
types.UDim.toPod(roblox.Y),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Vector2 = {
|
|
||||||
fromPod = unpackDecoder(Vector2.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
serializeFloat(roblox.X),
|
|
||||||
serializeFloat(roblox.Y),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Vector2int16 = {
|
|
||||||
fromPod = unpackDecoder(Vector2int16.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {roblox.X, roblox.Y}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Vector3 = {
|
|
||||||
fromPod = unpackDecoder(Vector3.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {
|
|
||||||
serializeFloat(roblox.X),
|
|
||||||
serializeFloat(roblox.Y),
|
|
||||||
serializeFloat(roblox.Z),
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
|
|
||||||
Vector3int16 = {
|
|
||||||
fromPod = unpackDecoder(Vector3int16.new),
|
|
||||||
|
|
||||||
toPod = function(roblox)
|
|
||||||
return {roblox.X, roblox.Y, roblox.Z}
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local EncodedValue = {}
|
|
||||||
|
|
||||||
function EncodedValue.decode(encodedValue)
|
|
||||||
local typeImpl = types[encodedValue.Type]
|
|
||||||
if typeImpl == nil then
|
|
||||||
return false, "Couldn't decode value " .. tostring(encodedValue.Type)
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, typeImpl.fromPod(encodedValue.Value)
|
|
||||||
end
|
|
||||||
|
|
||||||
function EncodedValue.encode(rbxValue, propertyType)
|
|
||||||
assert(propertyType ~= nil, "Property type descriptor is required")
|
|
||||||
|
|
||||||
local typeImpl = types[propertyType]
|
|
||||||
if typeImpl == nil then
|
|
||||||
return false, ("Missing encoder for property type %q"):format(propertyType)
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, {
|
|
||||||
Type = propertyType,
|
|
||||||
Value = typeImpl.toPod(rbxValue),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return EncodedValue
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
return function()
|
|
||||||
local HttpService = game:GetService("HttpService")
|
|
||||||
|
|
||||||
local EncodedValue = require(script.Parent.EncodedValue)
|
|
||||||
local allValues = require(script.Parent.allValues)
|
|
||||||
|
|
||||||
local function deepEq(a, b)
|
|
||||||
if typeof(a) ~= typeof(b) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local ty = typeof(a)
|
|
||||||
|
|
||||||
if ty == "table" then
|
|
||||||
local visited = {}
|
|
||||||
|
|
||||||
for key, valueA in pairs(a) do
|
|
||||||
visited[key] = true
|
|
||||||
|
|
||||||
if not deepEq(valueA, b[key]) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for key, valueB in pairs(b) do
|
|
||||||
if visited[key] then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
if not deepEq(valueB, a[key]) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return a == b
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local extraAssertions = {
|
|
||||||
CFrame = function(value)
|
|
||||||
expect(value).to.equal(CFrame.new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
for testName, testEntry in pairs(allValues) do
|
|
||||||
it("round trip " .. testName, function()
|
|
||||||
local ok, decoded = EncodedValue.decode(testEntry.value)
|
|
||||||
assert(ok, decoded)
|
|
||||||
|
|
||||||
if extraAssertions[testName] ~= nil then
|
|
||||||
extraAssertions[testName](decoded)
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok, encoded = EncodedValue.encode(decoded, testEntry.ty)
|
|
||||||
assert(ok, encoded)
|
|
||||||
|
|
||||||
if not deepEq(encoded, testEntry.value) then
|
|
||||||
local expected = HttpService:JSONEncode(testEntry.value)
|
|
||||||
local actual = HttpService:JSONEncode(encoded)
|
|
||||||
|
|
||||||
local message = string.format(
|
|
||||||
"Round-trip results did not match.\nExpected:\n%s\nActual:\n%s",
|
|
||||||
expected, actual
|
|
||||||
)
|
|
||||||
|
|
||||||
error(message)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
2
plugin/rbx_dom_lua/README.md
Normal file
2
plugin/rbx_dom_lua/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# rbx_dom_lua
|
||||||
|
Roblox Lua implementation of rbx-dom mechanisms, intended to work with rbx_dom_weak and friends.
|
||||||
@@ -1,345 +0,0 @@
|
|||||||
{
|
|
||||||
"Axes": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Axes",
|
|
||||||
"Value": [
|
|
||||||
"X",
|
|
||||||
"Y",
|
|
||||||
"Z"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Axes"
|
|
||||||
},
|
|
||||||
"BinaryString": {
|
|
||||||
"value": {
|
|
||||||
"Type": "BinaryString",
|
|
||||||
"Value": "SGVsbG8h"
|
|
||||||
},
|
|
||||||
"ty": "BinaryString"
|
|
||||||
},
|
|
||||||
"Bool": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Bool",
|
|
||||||
"Value": true
|
|
||||||
},
|
|
||||||
"ty": "Bool"
|
|
||||||
},
|
|
||||||
"BrickColor": {
|
|
||||||
"value": {
|
|
||||||
"Type": "BrickColor",
|
|
||||||
"Value": 1004
|
|
||||||
},
|
|
||||||
"ty": "BrickColor"
|
|
||||||
},
|
|
||||||
"CFrame": {
|
|
||||||
"value": {
|
|
||||||
"Type": "CFrame",
|
|
||||||
"Value": {
|
|
||||||
"Position": [
|
|
||||||
1.0,
|
|
||||||
2.0,
|
|
||||||
3.0
|
|
||||||
],
|
|
||||||
"Orientation": [
|
|
||||||
[
|
|
||||||
4.0,
|
|
||||||
5.0,
|
|
||||||
6.0
|
|
||||||
],
|
|
||||||
[
|
|
||||||
7.0,
|
|
||||||
8.0,
|
|
||||||
9.0
|
|
||||||
],
|
|
||||||
[
|
|
||||||
10.0,
|
|
||||||
11.0,
|
|
||||||
12.0
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ty": "CFrame"
|
|
||||||
},
|
|
||||||
"Color3": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Color3",
|
|
||||||
"Value": [
|
|
||||||
1.0,
|
|
||||||
2.0,
|
|
||||||
3.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Color3"
|
|
||||||
},
|
|
||||||
"Color3uint8": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Color3uint8",
|
|
||||||
"Value": [
|
|
||||||
0,
|
|
||||||
128,
|
|
||||||
255
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Color3uint8"
|
|
||||||
},
|
|
||||||
"ColorSequence": {
|
|
||||||
"value": {
|
|
||||||
"Type": "ColorSequence",
|
|
||||||
"Value": {
|
|
||||||
"Keypoints": [
|
|
||||||
{
|
|
||||||
"Time": 0.0,
|
|
||||||
"Color": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
0.5
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Time": 1.0,
|
|
||||||
"Color": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ty": "ColorSequence"
|
|
||||||
},
|
|
||||||
"Content": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Content",
|
|
||||||
"Value": "rbxassetid://12345"
|
|
||||||
},
|
|
||||||
"ty": "Content"
|
|
||||||
},
|
|
||||||
"Enum": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Enum",
|
|
||||||
"Value": 1234
|
|
||||||
},
|
|
||||||
"ty": "Enum"
|
|
||||||
},
|
|
||||||
"Faces": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Faces",
|
|
||||||
"Value": [
|
|
||||||
"Right",
|
|
||||||
"Top",
|
|
||||||
"Back",
|
|
||||||
"Left",
|
|
||||||
"Bottom",
|
|
||||||
"Front"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Faces"
|
|
||||||
},
|
|
||||||
"Float32": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Float32",
|
|
||||||
"Value": 15.0
|
|
||||||
},
|
|
||||||
"ty": "Float32"
|
|
||||||
},
|
|
||||||
"Float64": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Float64",
|
|
||||||
"Value": 15123.0
|
|
||||||
},
|
|
||||||
"ty": "Float64"
|
|
||||||
},
|
|
||||||
"Int32": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Int32",
|
|
||||||
"Value": 6014
|
|
||||||
},
|
|
||||||
"ty": "Int32"
|
|
||||||
},
|
|
||||||
"Int64": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Int64",
|
|
||||||
"Value": 23491023
|
|
||||||
},
|
|
||||||
"ty": "Int64"
|
|
||||||
},
|
|
||||||
"NumberRange": {
|
|
||||||
"value": {
|
|
||||||
"Type": "NumberRange",
|
|
||||||
"Value": [
|
|
||||||
-36.0,
|
|
||||||
94.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "NumberRange"
|
|
||||||
},
|
|
||||||
"NumberSequence": {
|
|
||||||
"value": {
|
|
||||||
"Type": "NumberSequence",
|
|
||||||
"Value": {
|
|
||||||
"Keypoints": [
|
|
||||||
{
|
|
||||||
"Time": 0.0,
|
|
||||||
"Value": 5.0,
|
|
||||||
"Envelope": 2.0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Time": 1.0,
|
|
||||||
"Value": 22.0,
|
|
||||||
"Envelope": 0.0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ty": "NumberSequence"
|
|
||||||
},
|
|
||||||
"PhysicalProperties-Custom": {
|
|
||||||
"value": {
|
|
||||||
"Type": "PhysicalProperties",
|
|
||||||
"Value": {
|
|
||||||
"Density": 0.5,
|
|
||||||
"Friction": 1.0,
|
|
||||||
"Elasticity": 0.0,
|
|
||||||
"FrictionWeight": 50.0,
|
|
||||||
"ElasticityWeight": 25.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ty": "PhysicalProperties"
|
|
||||||
},
|
|
||||||
"PhysicalProperties-Default": {
|
|
||||||
"value": {
|
|
||||||
"Type": "PhysicalProperties",
|
|
||||||
"Value": "Default"
|
|
||||||
},
|
|
||||||
"ty": "PhysicalProperties"
|
|
||||||
},
|
|
||||||
"Ray": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Ray",
|
|
||||||
"Value": {
|
|
||||||
"Origin": [
|
|
||||||
1.0,
|
|
||||||
2.0,
|
|
||||||
3.0
|
|
||||||
],
|
|
||||||
"Direction": [
|
|
||||||
4.0,
|
|
||||||
5.0,
|
|
||||||
6.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ty": "Ray"
|
|
||||||
},
|
|
||||||
"Rect": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Rect",
|
|
||||||
"Value": [
|
|
||||||
[
|
|
||||||
0.0,
|
|
||||||
5.0
|
|
||||||
],
|
|
||||||
[
|
|
||||||
10.0,
|
|
||||||
15.0
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Rect"
|
|
||||||
},
|
|
||||||
"Region3int16": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Region3int16",
|
|
||||||
"Value": [
|
|
||||||
[
|
|
||||||
-10,
|
|
||||||
-5,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
10,
|
|
||||||
15
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Region3int16"
|
|
||||||
},
|
|
||||||
"String": {
|
|
||||||
"value": {
|
|
||||||
"Type": "String",
|
|
||||||
"Value": "Hello, world!"
|
|
||||||
},
|
|
||||||
"ty": "String"
|
|
||||||
},
|
|
||||||
"UDim": {
|
|
||||||
"value": {
|
|
||||||
"Type": "UDim",
|
|
||||||
"Value": [
|
|
||||||
1.0,
|
|
||||||
32
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "UDim"
|
|
||||||
},
|
|
||||||
"UDim2": {
|
|
||||||
"value": {
|
|
||||||
"Type": "UDim2",
|
|
||||||
"Value": [
|
|
||||||
[
|
|
||||||
-1.0,
|
|
||||||
100
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1.0,
|
|
||||||
-100
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "UDim2"
|
|
||||||
},
|
|
||||||
"Vector2": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Vector2",
|
|
||||||
"Value": [
|
|
||||||
-50.0,
|
|
||||||
50.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Vector2"
|
|
||||||
},
|
|
||||||
"Vector2int16": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Vector2int16",
|
|
||||||
"Value": [
|
|
||||||
-300,
|
|
||||||
300
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Vector2int16"
|
|
||||||
},
|
|
||||||
"Vector3": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Vector3",
|
|
||||||
"Value": [
|
|
||||||
-300.0,
|
|
||||||
0.0,
|
|
||||||
1500.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Vector3"
|
|
||||||
},
|
|
||||||
"Vector3int16": {
|
|
||||||
"value": {
|
|
||||||
"Type": "Vector3int16",
|
|
||||||
"Value": [
|
|
||||||
60,
|
|
||||||
37,
|
|
||||||
-450
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ty": "Vector3int16"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "empty_folder",
|
"name": "rbx_dom_lua",
|
||||||
"tree": {
|
"tree": {
|
||||||
"$path": "src"
|
"$path": "src"
|
||||||
}
|
}
|
||||||
242
plugin/rbx_dom_lua/src/EncodedValue.lua
Normal file
242
plugin/rbx_dom_lua/src/EncodedValue.lua
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
local base64 = require(script.Parent.base64)
|
||||||
|
|
||||||
|
local function identity(...)
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpackDecoder(f)
|
||||||
|
return function(value)
|
||||||
|
return f(unpack(value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function serializeFloat(value)
|
||||||
|
-- TODO: Figure out a better way to serialize infinity and NaN, neither of
|
||||||
|
-- which fit into JSON.
|
||||||
|
if value == math.huge or value == -math.huge then
|
||||||
|
return 999999999 * math.sign(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
local encoders
|
||||||
|
encoders = {
|
||||||
|
Bool = identity,
|
||||||
|
Content = identity,
|
||||||
|
Float32 = serializeFloat,
|
||||||
|
Float64 = serializeFloat,
|
||||||
|
Int32 = identity,
|
||||||
|
Int64 = identity,
|
||||||
|
String = identity,
|
||||||
|
|
||||||
|
BinaryString = base64.encode,
|
||||||
|
SharedString = base64.encode,
|
||||||
|
|
||||||
|
BrickColor = function(value)
|
||||||
|
return value.Number
|
||||||
|
end,
|
||||||
|
|
||||||
|
CFrame = function(value)
|
||||||
|
return {value:GetComponents()}
|
||||||
|
end,
|
||||||
|
Color3 = function(value)
|
||||||
|
return {value.r, value.g, value.b}
|
||||||
|
end,
|
||||||
|
NumberRange = function(value)
|
||||||
|
return {value.Min, value.Max}
|
||||||
|
end,
|
||||||
|
NumberSequence = function(value)
|
||||||
|
local keypoints = {}
|
||||||
|
|
||||||
|
for index, keypoint in ipairs(value.Keypoints) do
|
||||||
|
keypoints[index] = {
|
||||||
|
Time = keypoint.Time,
|
||||||
|
Value = keypoint.Value,
|
||||||
|
Envelope = keypoint.Envelope,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
Keypoints = keypoints,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
ColorSequence = function(value)
|
||||||
|
local keypoints = {}
|
||||||
|
|
||||||
|
for index, keypoint in ipairs(value.Keypoints) do
|
||||||
|
keypoints[index] = {
|
||||||
|
Time = keypoint.Time,
|
||||||
|
Color = encoders.Color3(keypoint.Value),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
Keypoints = keypoints,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
Rect = function(value)
|
||||||
|
return {
|
||||||
|
Min = {value.Min.X, value.Min.Y},
|
||||||
|
Max = {value.Max.X, value.Max.Y},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
UDim = function(value)
|
||||||
|
return {value.Scale, value.Offset}
|
||||||
|
end,
|
||||||
|
UDim2 = function(value)
|
||||||
|
return {value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset}
|
||||||
|
end,
|
||||||
|
Vector2 = function(value)
|
||||||
|
return {
|
||||||
|
serializeFloat(value.X),
|
||||||
|
serializeFloat(value.Y),
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
Vector2int16 = function(value)
|
||||||
|
return {value.X, value.Y}
|
||||||
|
end,
|
||||||
|
Vector3 = function(value)
|
||||||
|
return {
|
||||||
|
serializeFloat(value.X),
|
||||||
|
serializeFloat(value.Y),
|
||||||
|
serializeFloat(value.Z),
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
Vector3int16 = function(value)
|
||||||
|
return {value.X, value.Y, value.Z}
|
||||||
|
end,
|
||||||
|
|
||||||
|
PhysicalProperties = function(value)
|
||||||
|
if value == nil then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
Density = value.Density,
|
||||||
|
Friction = value.Friction,
|
||||||
|
Elasticity = value.Elasticity,
|
||||||
|
FrictionWeight = value.FrictionWeight,
|
||||||
|
ElasticityWeight = value.ElasticityWeight,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
Ref = function(value)
|
||||||
|
return nil
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local decoders = {
|
||||||
|
Bool = identity,
|
||||||
|
Content = identity,
|
||||||
|
Enum = identity,
|
||||||
|
Float32 = identity,
|
||||||
|
Float64 = identity,
|
||||||
|
Int32 = identity,
|
||||||
|
Int64 = identity,
|
||||||
|
String = identity,
|
||||||
|
|
||||||
|
BinaryString = base64.decode,
|
||||||
|
SharedString = base64.decode,
|
||||||
|
|
||||||
|
BrickColor = BrickColor.new,
|
||||||
|
|
||||||
|
CFrame = unpackDecoder(CFrame.new),
|
||||||
|
Color3 = unpackDecoder(Color3.new),
|
||||||
|
Color3uint8 = unpackDecoder(Color3.fromRGB),
|
||||||
|
NumberRange = unpackDecoder(NumberRange.new),
|
||||||
|
UDim = unpackDecoder(UDim.new),
|
||||||
|
UDim2 = unpackDecoder(UDim2.new),
|
||||||
|
Vector2 = unpackDecoder(Vector2.new),
|
||||||
|
Vector2int16 = unpackDecoder(Vector2int16.new),
|
||||||
|
Vector3 = unpackDecoder(Vector3.new),
|
||||||
|
Vector3int16 = unpackDecoder(Vector3int16.new),
|
||||||
|
|
||||||
|
Rect = function(value)
|
||||||
|
return Rect.new(value.Min[1], value.Min[2], value.Max[1], value.Max[2])
|
||||||
|
end,
|
||||||
|
|
||||||
|
NumberSequence = function(value)
|
||||||
|
local keypoints = {}
|
||||||
|
|
||||||
|
for index, keypoint in ipairs(value.Keypoints) do
|
||||||
|
keypoints[index] = NumberSequenceKeypoint.new(
|
||||||
|
keypoint.Time,
|
||||||
|
keypoint.Value,
|
||||||
|
keypoint.Envelope
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
return NumberSequence.new(keypoints)
|
||||||
|
end,
|
||||||
|
|
||||||
|
ColorSequence = function(value)
|
||||||
|
local keypoints = {}
|
||||||
|
|
||||||
|
for index, keypoint in ipairs(value.Keypoints) do
|
||||||
|
keypoints[index] = ColorSequenceKeypoint.new(
|
||||||
|
keypoint.Time,
|
||||||
|
Color3.new(unpack(keypoint.Color))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ColorSequence.new(keypoints)
|
||||||
|
end,
|
||||||
|
|
||||||
|
PhysicalProperties = function(properties)
|
||||||
|
if properties == nil then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return PhysicalProperties.new(
|
||||||
|
properties.Density,
|
||||||
|
properties.Friction,
|
||||||
|
properties.Elasticity,
|
||||||
|
properties.FrictionWeight,
|
||||||
|
properties.ElasticityWeight
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
Ref = function()
|
||||||
|
return nil
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local EncodedValue = {}
|
||||||
|
|
||||||
|
function EncodedValue.decode(encodedValue)
|
||||||
|
local decoder = decoders[encodedValue.Type]
|
||||||
|
if decoder ~= nil then
|
||||||
|
return true, decoder(encodedValue.Value)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false, "Couldn't decode value " .. tostring(encodedValue.Type)
|
||||||
|
end
|
||||||
|
|
||||||
|
function EncodedValue.encode(rbxValue, propertyType)
|
||||||
|
assert(propertyType ~= nil, "Property type descriptor is required")
|
||||||
|
|
||||||
|
if propertyType.type == "Data" then
|
||||||
|
local encoder = encoders[propertyType.name]
|
||||||
|
|
||||||
|
if encoder == nil then
|
||||||
|
return false, ("Missing encoder for property type %q"):format(propertyType.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
if encoder ~= nil then
|
||||||
|
return true, {
|
||||||
|
Type = propertyType.name,
|
||||||
|
Value = encoder(rbxValue),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
elseif propertyType.type == "Enum" then
|
||||||
|
return true, {
|
||||||
|
Type = "Enum",
|
||||||
|
Value = rbxValue.Value,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return false, ("Unknown property descriptor type %q"):format(tostring(propertyType.type))
|
||||||
|
end
|
||||||
|
|
||||||
|
return EncodedValue
|
||||||
127
plugin/rbx_dom_lua/src/EncodedValue.spec.lua
Normal file
127
plugin/rbx_dom_lua/src/EncodedValue.spec.lua
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
return function()
|
||||||
|
local RbxDom = require(script.Parent)
|
||||||
|
local EncodedValue = require(script.Parent.EncodedValue)
|
||||||
|
|
||||||
|
it("should decode Rect values", function()
|
||||||
|
local input = {
|
||||||
|
Type = "Rect",
|
||||||
|
Value = {
|
||||||
|
Min = {1, 2},
|
||||||
|
Max = {3, 4},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local output = Rect.new(1, 2, 3, 4)
|
||||||
|
|
||||||
|
local ok, decoded = EncodedValue.decode(input)
|
||||||
|
|
||||||
|
assert(ok, decoded)
|
||||||
|
expect(decoded).to.equal(output)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should decode ColorSequence values", function()
|
||||||
|
local input = {
|
||||||
|
Type = "ColorSequence",
|
||||||
|
Value = {
|
||||||
|
Keypoints = {
|
||||||
|
{
|
||||||
|
Time = 0,
|
||||||
|
Color = { 0.12, 0.34, 0.56 },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Time = 1,
|
||||||
|
Color = { 0.13, 0.33, 0.37 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local output = ColorSequence.new({
|
||||||
|
ColorSequenceKeypoint.new(0, Color3.new(0.12, 0.34, 0.56)),
|
||||||
|
ColorSequenceKeypoint.new(1, Color3.new(0.13, 0.33, 0.37)),
|
||||||
|
})
|
||||||
|
|
||||||
|
local ok, decoded = EncodedValue.decode(input)
|
||||||
|
assert(ok, decoded)
|
||||||
|
expect(decoded).to.equal(output)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should decode NumberSequence values", function()
|
||||||
|
local input = {
|
||||||
|
Type = "NumberSequence",
|
||||||
|
Value = {
|
||||||
|
Keypoints = {
|
||||||
|
{
|
||||||
|
Time = 0,
|
||||||
|
Value = 0.5,
|
||||||
|
Envelope = 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Time = 1,
|
||||||
|
Value = 0.5,
|
||||||
|
Envelope = 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local output = NumberSequence.new({
|
||||||
|
NumberSequenceKeypoint.new(0, 0.5, 0),
|
||||||
|
NumberSequenceKeypoint.new(1, 0.5, 0),
|
||||||
|
})
|
||||||
|
|
||||||
|
local ok, decoded = EncodedValue.decode(input)
|
||||||
|
assert(ok, decoded)
|
||||||
|
expect(decoded).to.equal(output)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should decode PhysicalProperties values", function()
|
||||||
|
local input = {
|
||||||
|
Type = "PhysicalProperties",
|
||||||
|
Value = {
|
||||||
|
Density = 0.1,
|
||||||
|
Friction = 0.2,
|
||||||
|
Elasticity = 0.3,
|
||||||
|
FrictionWeight = 0.4,
|
||||||
|
ElasticityWeight = 0.5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local output = PhysicalProperties.new(
|
||||||
|
0.1,
|
||||||
|
0.2,
|
||||||
|
0.3,
|
||||||
|
0.4,
|
||||||
|
0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
local ok, decoded = EncodedValue.decode(input)
|
||||||
|
assert(ok, decoded)
|
||||||
|
expect(decoded).to.equal(output)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- This part of rbx_dom_lua needs some work still.
|
||||||
|
itSKIP("should encode Rect values", function()
|
||||||
|
local input = Rect.new(10, 20, 30, 40)
|
||||||
|
|
||||||
|
local output = {
|
||||||
|
Type = "Rect",
|
||||||
|
Value = {
|
||||||
|
Min = {10, 20},
|
||||||
|
Max = {30, 40},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local descriptor = RbxDom.findCanonicalPropertyDescriptor("ImageLabel", "SliceCenter")
|
||||||
|
local ok, encoded = EncodedValue.encode(input, descriptor)
|
||||||
|
|
||||||
|
assert(ok, encoded)
|
||||||
|
expect(encoded.Type).to.equal(output.Type)
|
||||||
|
expect(encoded.Value.Min[1]).to.equal(output.Value.Min[1])
|
||||||
|
expect(encoded.Value.Min[2]).to.equal(output.Value.Min[2])
|
||||||
|
expect(encoded.Value.Max[1]).to.equal(output.Value.Max[1])
|
||||||
|
expect(encoded.Value.Max[2]).to.equal(output.Value.Max[2])
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -21,7 +21,7 @@ end
|
|||||||
|
|
||||||
function PropertyDescriptor.fromRaw(data, className, propertyName)
|
function PropertyDescriptor.fromRaw(data, className, propertyName)
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
scriptability = data.Scriptability,
|
scriptability = data.scriptability,
|
||||||
className = className,
|
className = className,
|
||||||
name = propertyName,
|
name = propertyName,
|
||||||
}, PropertyDescriptor)
|
}, PropertyDescriptor)
|
||||||
20114
plugin/rbx_dom_lua/src/ReflectionDatabase/classes.lua
Normal file
20114
plugin/rbx_dom_lua/src/ReflectionDatabase/classes.lua
Normal file
File diff suppressed because it is too large
Load Diff
3
plugin/rbx_dom_lua/src/ReflectionDatabase/init.lua
Normal file
3
plugin/rbx_dom_lua/src/ReflectionDatabase/init.lua
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
return {
|
||||||
|
classes = require(script.classes)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
local database = require(script.database)
|
local ReflectionDatabase = require(script.ReflectionDatabase)
|
||||||
local Error = require(script.Error)
|
local Error = require(script.Error)
|
||||||
local PropertyDescriptor = require(script.PropertyDescriptor)
|
local PropertyDescriptor = require(script.PropertyDescriptor)
|
||||||
|
|
||||||
@@ -6,31 +6,29 @@ local function findCanonicalPropertyDescriptor(className, propertyName)
|
|||||||
local currentClassName = className
|
local currentClassName = className
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
local currentClass = database.Classes[currentClassName]
|
local currentClass = ReflectionDatabase.classes[currentClassName]
|
||||||
|
|
||||||
if currentClass == nil then
|
if currentClass == nil then
|
||||||
return currentClass
|
return currentClass
|
||||||
end
|
end
|
||||||
|
|
||||||
local propertyData = currentClass.Properties[propertyName]
|
local propertyData = currentClass.properties[propertyName]
|
||||||
if propertyData ~= nil then
|
if propertyData ~= nil then
|
||||||
local canonicalData = propertyData.Kind.Canonical
|
if propertyData.isCanonical then
|
||||||
if canonicalData ~= nil then
|
|
||||||
return PropertyDescriptor.fromRaw(propertyData, currentClassName, propertyName)
|
return PropertyDescriptor.fromRaw(propertyData, currentClassName, propertyName)
|
||||||
end
|
end
|
||||||
|
|
||||||
local aliasData = propertyData.Kind.Alias
|
if propertyData.canonicalName ~= nil then
|
||||||
if aliasData ~= nil then
|
|
||||||
return PropertyDescriptor.fromRaw(
|
return PropertyDescriptor.fromRaw(
|
||||||
currentClass.properties[aliasData.AliasFor],
|
currentClass.properties[propertyData.canonicalName],
|
||||||
currentClassName,
|
currentClassName,
|
||||||
aliasData.AliasFor)
|
propertyData.canonicalName)
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
currentClassName = currentClass.Superclass
|
currentClassName = currentClass.superclass
|
||||||
until currentClassName == nil
|
until currentClassName == nil
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
35
plugin/rbx_dom_lua/test-place.project.json
Normal file
35
plugin/rbx_dom_lua/test-place.project.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "rbx_dom_lua test place",
|
||||||
|
"tree": {
|
||||||
|
"$className": "DataModel",
|
||||||
|
"ReplicatedStorage": {
|
||||||
|
"$className": "ReplicatedStorage",
|
||||||
|
|
||||||
|
"RbxDom": {
|
||||||
|
"$path": "src"
|
||||||
|
},
|
||||||
|
"TestEZ": {
|
||||||
|
"$path": "modules/testez/lib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ServerScriptService": {
|
||||||
|
"$className": "ServerScriptService",
|
||||||
|
|
||||||
|
"Run Tests": {
|
||||||
|
"$path": "test.server.lua"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Players": {
|
||||||
|
"$className": "Players",
|
||||||
|
"$properties": {
|
||||||
|
"CharacterAutoLoads": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"HttpService": {
|
||||||
|
"$className": "HttpService",
|
||||||
|
"$properties": {
|
||||||
|
"HttpEnabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
plugin/rbx_dom_lua/test.server.lua
Normal file
7
plugin/rbx_dom_lua/test.server.lua
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
|
||||||
|
local LIB_ROOT = ReplicatedStorage.RbxDom
|
||||||
|
|
||||||
|
local TestEZ = require(ReplicatedStorage.TestEZ)
|
||||||
|
|
||||||
|
TestEZ.TestBootstrap:run({LIB_ROOT})
|
||||||
@@ -205,7 +205,7 @@ function SettingsPage:render()
|
|||||||
TwoWaySync = e(Setting, {
|
TwoWaySync = e(Setting, {
|
||||||
id = "twoWaySync",
|
id = "twoWaySync",
|
||||||
name = "Two-Way Sync",
|
name = "Two-Way Sync",
|
||||||
description = "EXPERIMENTAL! Editing files in Studio will sync them into the filesystem",
|
description = "Editing files in Studio will sync them into the filesystem",
|
||||||
transparency = self.props.transparency,
|
transparency = self.props.transparency,
|
||||||
layoutOrder = 2,
|
layoutOrder = 2,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ local isDevBuild = script.Parent.Parent:FindFirstChild("ROJO_DEV_BUILD") ~= nil
|
|||||||
return strict("Config", {
|
return strict("Config", {
|
||||||
isDevBuild = isDevBuild,
|
isDevBuild = isDevBuild,
|
||||||
codename = "Epiphany",
|
codename = "Epiphany",
|
||||||
version = {7, 0, 0, "-alpha.4"},
|
version = {6, 1, 0},
|
||||||
expectedServerVersionString = "7.0 or newer",
|
expectedServerVersionString = "6.0 or newer",
|
||||||
protocolVersion = 4,
|
protocolVersion = 3,
|
||||||
defaultHost = "localhost",
|
defaultHost = "localhost",
|
||||||
defaultPort = 34872,
|
defaultPort = 34872,
|
||||||
})
|
})
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
local StudioService = game:GetService("StudioService")
|
local StudioService = game:GetService("StudioService")
|
||||||
local RunService = game:GetService("RunService")
|
|
||||||
|
|
||||||
local Log = require(script.Parent.Parent.Log)
|
local Log = require(script.Parent.Parent.Log)
|
||||||
local Fmt = require(script.Parent.Parent.Fmt)
|
local Fmt = require(script.Parent.Parent.Fmt)
|
||||||
@@ -112,7 +111,6 @@ function ServeSession:start()
|
|||||||
self.__apiContext:connect()
|
self.__apiContext:connect()
|
||||||
:andThen(function(serverInfo)
|
:andThen(function(serverInfo)
|
||||||
self:__setStatus(Status.Connected, serverInfo.projectName)
|
self:__setStatus(Status.Connected, serverInfo.projectName)
|
||||||
self:__applyGameAndPlaceId(serverInfo)
|
|
||||||
|
|
||||||
local rootInstanceId = serverInfo.rootInstanceId
|
local rootInstanceId = serverInfo.rootInstanceId
|
||||||
|
|
||||||
@@ -130,16 +128,6 @@ function ServeSession:stop()
|
|||||||
self:__stopInternal()
|
self:__stopInternal()
|
||||||
end
|
end
|
||||||
|
|
||||||
function ServeSession:__applyGameAndPlaceId(serverInfo)
|
|
||||||
if serverInfo.gameId ~= nil then
|
|
||||||
game:SetUniverseId(serverInfo.gameId)
|
|
||||||
end
|
|
||||||
|
|
||||||
if serverInfo.placeId ~= nil then
|
|
||||||
game:SetPlaceId(serverInfo.placeId)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ServeSession:__onActiveScriptChanged(activeScript)
|
function ServeSession:__onActiveScriptChanged(activeScript)
|
||||||
if not self.__openScriptsExternally then
|
if not self.__openScriptsExternally then
|
||||||
Log.trace("Not opening script {} because feature not enabled.", activeScript)
|
Log.trace("Not opening script {} because feature not enabled.", activeScript)
|
||||||
@@ -162,18 +150,10 @@ function ServeSession:__onActiveScriptChanged(activeScript)
|
|||||||
|
|
||||||
Log.debug("Trying to open script {} externally...", activeScript)
|
Log.debug("Trying to open script {} externally...", activeScript)
|
||||||
|
|
||||||
-- Force-close the script inside Studio... with a small delay in the middle
|
-- Force-close the script inside Studio
|
||||||
-- to prevent Studio from crashing.
|
local existingParent = activeScript.Parent
|
||||||
spawn(function()
|
activeScript.Parent = nil
|
||||||
local existingParent = activeScript.Parent
|
activeScript.Parent = existingParent
|
||||||
activeScript.Parent = nil
|
|
||||||
|
|
||||||
for i = 1, 3 do
|
|
||||||
RunService.Heartbeat:Wait()
|
|
||||||
end
|
|
||||||
|
|
||||||
activeScript.Parent = existingParent
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Notify the Rojo server to open this script
|
-- Notify the Rojo server to open this script
|
||||||
self.__apiContext:open(scriptId)
|
self.__apiContext:open(scriptId)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ expression: contents
|
|||||||
<Item class="IntValue" referent="1">
|
<Item class="IntValue" referent="1">
|
||||||
<Properties>
|
<Properties>
|
||||||
<string name="Name">simple-model</string>
|
<string name="Name">simple-model</string>
|
||||||
<int64 name="Value">5</int64>
|
<int name="Value">5</int>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Item class="Folder" referent="2">
|
<Item class="Folder" referent="2">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
source: tests/tests/build.rs
|
|
||||||
expression: contents
|
|
||||||
---
|
|
||||||
<roblox version="4">
|
|
||||||
<Item class="DataModel" referent="0">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">unresolved-values</string>
|
|
||||||
</Properties>
|
|
||||||
<Item class="Lighting" referent="1">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">Lighting</string>
|
|
||||||
<Color3 name="Ambient">
|
|
||||||
<R>1</R>
|
|
||||||
<G>0</G>
|
|
||||||
<B>0</B>
|
|
||||||
</Color3>
|
|
||||||
<token name="Technology">1</token>
|
|
||||||
</Properties>
|
|
||||||
</Item>
|
|
||||||
<Item class="Workspace" referent="2">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">Workspace</string>
|
|
||||||
</Properties>
|
|
||||||
<Item class="BoolValue" referent="3">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">Bool</string>
|
|
||||||
<bool name="Value">true</bool>
|
|
||||||
</Properties>
|
|
||||||
</Item>
|
|
||||||
<Item class="Part" referent="4">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">Color</string>
|
|
||||||
<Color3 name="Color3uint8">
|
|
||||||
<R>0.5</R>
|
|
||||||
<G>0.25</G>
|
|
||||||
<B>0</B>
|
|
||||||
</Color3>
|
|
||||||
</Properties>
|
|
||||||
</Item>
|
|
||||||
<Item class="NumberValue" referent="5">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">Float</string>
|
|
||||||
<double name="Value">123.5</double>
|
|
||||||
</Properties>
|
|
||||||
</Item>
|
|
||||||
<Item class="IntValue" referent="6">
|
|
||||||
<Properties>
|
|
||||||
<string name="Name">Int</string>
|
|
||||||
<int64 name="Value">65</int64>
|
|
||||||
</Properties>
|
|
||||||
</Item>
|
|
||||||
</Item>
|
|
||||||
</Item>
|
|
||||||
</roblox>
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "unresolved-values",
|
|
||||||
"tree": {
|
|
||||||
"$className": "DataModel",
|
|
||||||
|
|
||||||
"Lighting": {
|
|
||||||
"$properties": {
|
|
||||||
"Technology": "Voxel",
|
|
||||||
"Ambient": [1, 0, 0]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"Workspace": {
|
|
||||||
"Color": {
|
|
||||||
"$className": "Part",
|
|
||||||
"$properties": {
|
|
||||||
"Color": [0.5, 0.25, 0]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"Bool": {
|
|
||||||
"$className": "BoolValue",
|
|
||||||
"$properties": {
|
|
||||||
"Value": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"Int": {
|
|
||||||
"$className": "IntValue",
|
|
||||||
"$properties": {
|
|
||||||
"Value": 65
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"Float": {
|
|
||||||
"$className": "NumberValue",
|
|
||||||
"$properties": {
|
|
||||||
"Value": 123.5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: add_folder
|
Name: add_folder
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
id-3:
|
id-3:
|
||||||
Children: []
|
Children: []
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: add_folder
|
Name: add_folder
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 0
|
messageCursor: 0
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: add_folder
|
projectName: add_folder
|
||||||
protocolVersion: 4
|
protocolVersion: 3
|
||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: edit_init
|
Name: edit_init
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties:
|
Properties:
|
||||||
Source:
|
Source:
|
||||||
Type: String
|
Type: String
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: edit_init
|
Name: edit_init
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties:
|
Properties:
|
||||||
Source:
|
Source:
|
||||||
Type: String
|
Type: String
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: edit_init
|
projectName: edit_init
|
||||||
protocolVersion: 4
|
protocolVersion: 3
|
||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: true
|
ignoreUnknownInstances: true
|
||||||
Name: empty
|
Name: empty
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 0
|
messageCursor: 0
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: empty
|
projectName: empty
|
||||||
protocolVersion: 4
|
protocolVersion: 3
|
||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
source: tests/tests/serve.rs
|
|
||||||
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
|
||||||
|
|
||||||
---
|
|
||||||
instances:
|
|
||||||
id-2:
|
|
||||||
Children:
|
|
||||||
- id-3
|
|
||||||
ClassName: Folder
|
|
||||||
Id: id-2
|
|
||||||
Metadata:
|
|
||||||
ignoreUnknownInstances: false
|
|
||||||
Name: empty_folder
|
|
||||||
Parent: "00000000000000000000000000000000"
|
|
||||||
Properties: {}
|
|
||||||
id-3:
|
|
||||||
Children: []
|
|
||||||
ClassName: Model
|
|
||||||
Id: id-3
|
|
||||||
Metadata:
|
|
||||||
ignoreUnknownInstances: false
|
|
||||||
Name: test
|
|
||||||
Parent: id-2
|
|
||||||
Properties: {}
|
|
||||||
messageCursor: 1
|
|
||||||
sessionId: id-1
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
source: tests/tests/serve.rs
|
|
||||||
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
|
||||||
|
|
||||||
---
|
|
||||||
instances:
|
|
||||||
id-2:
|
|
||||||
Children: []
|
|
||||||
ClassName: Folder
|
|
||||||
Id: id-2
|
|
||||||
Metadata:
|
|
||||||
ignoreUnknownInstances: false
|
|
||||||
Name: empty_folder
|
|
||||||
Parent: "00000000000000000000000000000000"
|
|
||||||
Properties: {}
|
|
||||||
messageCursor: 0
|
|
||||||
sessionId: id-1
|
|
||||||
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
source: tests/tests/serve.rs
|
|
||||||
expression: redactions.redacted_yaml(info)
|
|
||||||
|
|
||||||
---
|
|
||||||
expectedPlaceIds: ~
|
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: empty_folder
|
|
||||||
protocolVersion: 4
|
|
||||||
rootInstanceId: id-2
|
|
||||||
serverVersion: "[server-version]"
|
|
||||||
sessionId: id-1
|
|
||||||
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
---
|
|
||||||
source: tests/tests/serve.rs
|
|
||||||
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
|
||||||
|
|
||||||
---
|
|
||||||
messageCursor: 1
|
|
||||||
messages:
|
|
||||||
- added:
|
|
||||||
id-3:
|
|
||||||
Children: []
|
|
||||||
ClassName: Model
|
|
||||||
Id: id-3
|
|
||||||
Metadata:
|
|
||||||
ignoreUnknownInstances: false
|
|
||||||
Name: test
|
|
||||||
Parent: id-2
|
|
||||||
Properties: {}
|
|
||||||
removed: []
|
|
||||||
updated: []
|
|
||||||
sessionId: id-1
|
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: move_folder_of_stuff
|
Name: move_folder_of_stuff
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
id-3:
|
id-3:
|
||||||
Children:
|
Children:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: move_folder_of_stuff
|
Name: move_folder_of_stuff
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 0
|
messageCursor: 0
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: move_folder_of_stuff
|
projectName: move_folder_of_stuff
|
||||||
protocolVersion: 4
|
protocolVersion: 3
|
||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: remove_file
|
Name: remove_file
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
messageCursor: 1
|
messageCursor: 1
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: remove_file
|
Name: remove_file
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
id-3:
|
id-3:
|
||||||
Children: []
|
Children: []
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: remove_file
|
projectName: remove_file
|
||||||
protocolVersion: 4
|
protocolVersion: 3
|
||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: scripts
|
Name: scripts
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
id-3:
|
id-3:
|
||||||
Children: []
|
Children: []
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ instances:
|
|||||||
Metadata:
|
Metadata:
|
||||||
ignoreUnknownInstances: false
|
ignoreUnknownInstances: false
|
||||||
Name: scripts
|
Name: scripts
|
||||||
Parent: "00000000000000000000000000000000"
|
Parent: ~
|
||||||
Properties: {}
|
Properties: {}
|
||||||
id-3:
|
id-3:
|
||||||
Children: []
|
Children: []
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
---
|
---
|
||||||
source: tests/tests/serve.rs
|
source: tests/tests/serve.rs
|
||||||
expression: redactions.redacted_yaml(info)
|
expression: redactions.redacted_yaml(info)
|
||||||
|
|
||||||
---
|
---
|
||||||
expectedPlaceIds: ~
|
expectedPlaceIds: ~
|
||||||
gameId: ~
|
|
||||||
placeId: ~
|
|
||||||
projectName: scripts
|
projectName: scripts
|
||||||
protocolVersion: 4
|
protocolVersion: 3
|
||||||
rootInstanceId: id-2
|
rootInstanceId: id-2
|
||||||
serverVersion: "[server-version]"
|
serverVersion: "[server-version]"
|
||||||
sessionId: id-1
|
sessionId: id-1
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::{
|
|||||||
use crossbeam_channel::{select, Receiver, RecvError, Sender};
|
use crossbeam_channel::{select, Receiver, RecvError, Sender};
|
||||||
use jod_thread::JoinHandle;
|
use jod_thread::JoinHandle;
|
||||||
use memofs::{IoResultExt, Vfs, VfsEvent};
|
use memofs::{IoResultExt, Vfs, VfsEvent};
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
message_queue::MessageQueue,
|
message_queue::MessageQueue,
|
||||||
@@ -179,7 +179,7 @@ impl JobThreadContext {
|
|||||||
InstigatingSource::Path(path) => fs::remove_file(path).unwrap(),
|
InstigatingSource::Path(path) => fs::remove_file(path).unwrap(),
|
||||||
InstigatingSource::ProjectNode(_, _, _, _) => {
|
InstigatingSource::ProjectNode(_, _, _, _) => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Cannot remove instance {:?}, it's from a project file",
|
"Cannot remove instance {}, it's from a project file",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -187,12 +187,12 @@ impl JobThreadContext {
|
|||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Cannot remove instance {:?}, it is not an instigating source.",
|
"Cannot remove instance {}, it is not an instigating source.",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Cannot remove instance {:?}, it does not exist.", id);
|
log::warn!("Cannot remove instance {}, it does not exist.", id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ impl JobThreadContext {
|
|||||||
{
|
{
|
||||||
match instigating_source {
|
match instigating_source {
|
||||||
InstigatingSource::Path(path) => {
|
InstigatingSource::Path(path) => {
|
||||||
if let Some(Variant::String(value)) = changed_value {
|
if let Some(RbxValue::String { value }) = changed_value {
|
||||||
fs::write(path, value).unwrap();
|
fs::write(path, value).unwrap();
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Cannot change Source to non-string value.");
|
log::warn!("Cannot change Source to non-string value.");
|
||||||
@@ -227,14 +227,14 @@ impl JobThreadContext {
|
|||||||
}
|
}
|
||||||
InstigatingSource::ProjectNode(_, _, _, _) => {
|
InstigatingSource::ProjectNode(_, _, _, _) => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Cannot remove instance {:?}, it's from a project file",
|
"Cannot remove instance {}, it's from a project file",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Cannot update instance {:?}, it is not an instigating source.",
|
"Cannot update instance {}, it is not an instigating source.",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ impl JobThreadContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Cannot update instance {:?}, it does not exist.", id);
|
log::warn!("Cannot update instance {}, it does not exist.", id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ impl JobThreadContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: Ref) -> Option<AppliedPatchSet> {
|
fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: RbxId) -> Option<AppliedPatchSet> {
|
||||||
let metadata = tree
|
let metadata = tree
|
||||||
.get_metadata(id)
|
.get_metadata(id)
|
||||||
.expect("metadata missing for instance present in tree");
|
.expect("metadata missing for instance present in tree");
|
||||||
@@ -263,7 +263,7 @@ fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: Ref) -> Option<
|
|||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => {
|
None => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Instance {:?} did not have an instigating source, but was considered for an update.",
|
"Instance {} did not have an instigating source, but was considered for an update.",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
log::error!("This is a bug. Please file an issue!");
|
log::error!("This is a bug. Please file an issue!");
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ fn write_model(tree: &RojoTree, options: &BuildCommand) -> Result<(), anyhow::Er
|
|||||||
}
|
}
|
||||||
OutputKind::Rbxlx => {
|
OutputKind::Rbxlx => {
|
||||||
// Place files don't contain an entry for the DataModel, but our
|
// Place files don't contain an entry for the DataModel, but our
|
||||||
// WeakDom representation does.
|
// RbxTree representation does.
|
||||||
|
|
||||||
let root_instance = tree.get_instance(root_id).unwrap();
|
let root_instance = tree.get_instance(root_id).unwrap();
|
||||||
let top_level_ids = root_instance.children();
|
let top_level_ids = root_instance.children();
|
||||||
@@ -96,13 +96,17 @@ fn write_model(tree: &RojoTree, options: &BuildCommand) -> Result<(), anyhow::Er
|
|||||||
rbx_xml::to_writer(&mut file, tree.inner(), top_level_ids, xml_encode_config())?;
|
rbx_xml::to_writer(&mut file, tree.inner(), top_level_ids, xml_encode_config())?;
|
||||||
}
|
}
|
||||||
OutputKind::Rbxm => {
|
OutputKind::Rbxm => {
|
||||||
rbx_binary::to_writer_default(&mut file, tree.inner(), &[root_id])?;
|
rbx_binary::encode(tree.inner(), &[root_id], &mut file)?;
|
||||||
}
|
}
|
||||||
OutputKind::Rbxl => {
|
OutputKind::Rbxl => {
|
||||||
|
log::warn!("Support for building binary places (rbxl) is still experimental.");
|
||||||
|
log::warn!("Using the XML place format (rbxlx) is recommended instead.");
|
||||||
|
log::warn!("For more info, see https://github.com/rojo-rbx/rojo/issues/180");
|
||||||
|
|
||||||
let root_instance = tree.get_instance(root_id).unwrap();
|
let root_instance = tree.get_instance(root_id).unwrap();
|
||||||
let top_level_ids = root_instance.children();
|
let top_level_ids = root_instance.children();
|
||||||
|
|
||||||
rbx_binary::to_writer_default(&mut file, tree.inner(), top_level_ids)?;
|
rbx_binary::encode(tree.inner(), top_level_ids, &mut file)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ pub fn install_plugin() -> Result<()> {
|
|||||||
let tree = session.tree();
|
let tree = session.tree();
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
rbx_binary::to_writer_default(&mut file, tree.inner(), &[root_id])?;
|
rbx_binary::encode(tree.inner(), &[root_id], &mut file)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,21 @@ pub fn upload(options: UploadCommand) -> Result<(), anyhow::Error> {
|
|||||||
|
|
||||||
let tree = session.tree();
|
let tree = session.tree();
|
||||||
let inner_tree = tree.inner();
|
let inner_tree = tree.inner();
|
||||||
let root = inner_tree.root();
|
let root_id = inner_tree.get_root_id();
|
||||||
|
let root_instance = inner_tree.get_instance(root_id).unwrap();
|
||||||
|
|
||||||
let encode_ids = match root.class.as_str() {
|
let encode_ids = match root_instance.class_name.as_str() {
|
||||||
"DataModel" => root.children().to_vec(),
|
"DataModel" => root_instance.get_children_ids().to_vec(),
|
||||||
_ => vec![root.referent()],
|
_ => vec![root_id],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
log::trace!("Encoding binary model");
|
log::trace!("Encoding XML model");
|
||||||
rbx_binary::to_writer_default(&mut buffer, tree.inner(), &encode_ids)?;
|
let config = rbx_xml::EncodeOptions::new()
|
||||||
|
.property_behavior(rbx_xml::EncodePropertyBehavior::WriteUnknown);
|
||||||
|
|
||||||
|
rbx_xml::to_writer(&mut buffer, tree.inner(), &encode_ids, config)?;
|
||||||
do_upload(buffer, options.asset_id, &cookie)
|
do_upload(buffer, options.asset_id, &cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ mod message_queue;
|
|||||||
mod multimap;
|
mod multimap;
|
||||||
mod path_serializer;
|
mod path_serializer;
|
||||||
mod project;
|
mod project;
|
||||||
mod resolution;
|
|
||||||
mod serve_session;
|
mod serve_session;
|
||||||
mod session_id;
|
mod session_id;
|
||||||
mod snapshot;
|
mod snapshot;
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use rbx_dom_weak::UnresolvedRbxValue;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{glob::Glob, resolution::UnresolvedValue};
|
use crate::glob::Glob;
|
||||||
|
|
||||||
static PROJECT_FILENAME: &str = "default.project.json";
|
static PROJECT_FILENAME: &str = "default.project.json";
|
||||||
|
|
||||||
@@ -57,14 +58,6 @@ 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, sets the current place's place ID when connecting to the
|
|
||||||
/// Rojo server from Roblox Studio.
|
|
||||||
pub place_id: Option<u64>,
|
|
||||||
|
|
||||||
/// If specified, sets the current place's game ID when connecting to the
|
|
||||||
/// Rojo server from Roblox Studio.
|
|
||||||
pub game_id: Option<u64>,
|
|
||||||
|
|
||||||
/// A list of globs, relative to the folder the project file is in, that
|
/// A list of globs, relative to the folder the project file is in, that
|
||||||
/// match files that should be excluded if Rojo encounters them.
|
/// match files that should be excluded if Rojo encounters them.
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
@@ -190,7 +183,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: HashMap<String, UnresolvedRbxValue>,
|
||||||
|
|
||||||
/// Defines the behavior when Rojo encounters unknown instances in Roblox
|
/// Defines the behavior when Rojo encounters unknown instances in Roblox
|
||||||
/// Studio during live sync. `$ignoreUnknownInstances` should be considered
|
/// Studio during live sync. `$ignoreUnknownInstances` should be considered
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
use anyhow::format_err;
|
|
||||||
use rbx_dom_weak::types::{
|
|
||||||
Color3, Color3uint8, Content, Enum, Variant, VariantType, Vector2, Vector3,
|
|
||||||
};
|
|
||||||
use rbx_reflection::{DataType, PropertyDescriptor};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum UnresolvedValue {
|
|
||||||
FullyQualified(Variant),
|
|
||||||
Ambiguous(AmbiguousValue),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnresolvedValue {
|
|
||||||
pub fn resolve(self, class_name: &str, prop_name: &str) -> anyhow::Result<Variant> {
|
|
||||||
match self {
|
|
||||||
UnresolvedValue::FullyQualified(full) => Ok(full),
|
|
||||||
UnresolvedValue::Ambiguous(partial) => partial.resolve(class_name, prop_name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum AmbiguousValue {
|
|
||||||
Bool(bool),
|
|
||||||
String(String),
|
|
||||||
Number(f64),
|
|
||||||
Array2([f64; 2]),
|
|
||||||
Array3([f64; 3]),
|
|
||||||
Array4([f64; 4]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AmbiguousValue {
|
|
||||||
pub fn resolve(self, class_name: &str, prop_name: &str) -> anyhow::Result<Variant> {
|
|
||||||
let property = find_descriptor(class_name, prop_name)
|
|
||||||
.ok_or_else(|| format_err!("Unknown property {}.{}", class_name, prop_name))?;
|
|
||||||
|
|
||||||
match &property.data_type {
|
|
||||||
DataType::Enum(enum_name) => {
|
|
||||||
let database = rbx_reflection_database::get();
|
|
||||||
|
|
||||||
let enum_descriptor = database.enums.get(enum_name).ok_or_else(|| {
|
|
||||||
format_err!("Unknown enum {}. This is a Rojo bug!", enum_name)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let error = |what: &str| {
|
|
||||||
let sample_values = enum_descriptor
|
|
||||||
.items
|
|
||||||
.keys()
|
|
||||||
.take(3)
|
|
||||||
.map(|name| format!(r#""{}""#, name))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
format_err!(
|
|
||||||
"Invalid value for property {}.{}. Got {} but \
|
|
||||||
expected a member of the {} enum such as {}",
|
|
||||||
class_name,
|
|
||||||
prop_name,
|
|
||||||
what,
|
|
||||||
enum_name,
|
|
||||||
sample_values
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let value = match self {
|
|
||||||
AmbiguousValue::String(value) => value,
|
|
||||||
unresolved => return Err(error(unresolved.describe())),
|
|
||||||
};
|
|
||||||
|
|
||||||
let resolved = enum_descriptor
|
|
||||||
.items
|
|
||||||
.get(value.as_str())
|
|
||||||
.ok_or_else(|| error(value.as_str()))?;
|
|
||||||
|
|
||||||
Ok(Enum::from_u32(*resolved).into())
|
|
||||||
}
|
|
||||||
DataType::Value(variant_ty) => match (variant_ty, self) {
|
|
||||||
(VariantType::Bool, AmbiguousValue::Bool(value)) => Ok(value.into()),
|
|
||||||
|
|
||||||
(VariantType::Float32, AmbiguousValue::Number(value)) => Ok((value as f32).into()),
|
|
||||||
(VariantType::Float64, AmbiguousValue::Number(value)) => Ok(value.into()),
|
|
||||||
(VariantType::Int32, AmbiguousValue::Number(value)) => Ok((value as i32).into()),
|
|
||||||
(VariantType::Int64, AmbiguousValue::Number(value)) => Ok((value as i64).into()),
|
|
||||||
|
|
||||||
(VariantType::String, AmbiguousValue::String(value)) => Ok(value.into()),
|
|
||||||
(VariantType::Content, AmbiguousValue::String(value)) => {
|
|
||||||
Ok(Content::from(value).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
(VariantType::Vector2, AmbiguousValue::Array2(value)) => {
|
|
||||||
Ok(Vector2::new(value[0] as f32, value[1] as f32).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
(VariantType::Vector3, AmbiguousValue::Array3(value)) => {
|
|
||||||
Ok(Vector3::new(value[0] as f32, value[1] as f32, value[2] as f32).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
(VariantType::Color3, AmbiguousValue::Array3(value)) => {
|
|
||||||
Ok(Color3::new(value[0] as f32, value[1] as f32, value[2] as f32).into())
|
|
||||||
}
|
|
||||||
(VariantType::Color3uint8, AmbiguousValue::Array3(value)) => {
|
|
||||||
let value = Color3uint8::new(
|
|
||||||
(value[0] / 255.0) as u8,
|
|
||||||
(value[1] / 255.0) as u8,
|
|
||||||
(value[2] / 255.0) as u8,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(value.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, unresolved) => Err(format_err!(
|
|
||||||
"Wrong type of value for property {}.{}. Expected {:?}, got {}",
|
|
||||||
class_name,
|
|
||||||
prop_name,
|
|
||||||
variant_ty,
|
|
||||||
unresolved.describe(),
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
_ => Err(format_err!(
|
|
||||||
"Unknown data type for property {}.{}",
|
|
||||||
class_name,
|
|
||||||
prop_name
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn describe(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
AmbiguousValue::Bool(_) => "a bool",
|
|
||||||
AmbiguousValue::String(_) => "a string",
|
|
||||||
AmbiguousValue::Number(_) => "a number",
|
|
||||||
AmbiguousValue::Array2(_) => "an array of two numbers",
|
|
||||||
AmbiguousValue::Array3(_) => "an array of three numbers",
|
|
||||||
AmbiguousValue::Array4(_) => "an array of four numbers",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_descriptor(
|
|
||||||
class_name: &str,
|
|
||||||
prop_name: &str,
|
|
||||||
) -> Option<&'static PropertyDescriptor<'static>> {
|
|
||||||
let database = rbx_reflection_database::get();
|
|
||||||
let mut current_class_name = class_name;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let class = database.classes.get(current_class_name)?;
|
|
||||||
if let Some(descriptor) = class.properties.get(prop_name) {
|
|
||||||
return Some(descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
current_class_name = class.superclass.as_deref()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,7 @@ use std::{
|
|||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use memofs::IoResultExt;
|
use memofs::IoResultExt;
|
||||||
use memofs::Vfs;
|
use memofs::Vfs;
|
||||||
|
use rbx_dom_weak::RbxInstanceProperties;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -18,8 +19,8 @@ use crate::{
|
|||||||
project::{Project, ProjectError},
|
project::{Project, ProjectError},
|
||||||
session_id::SessionId,
|
session_id::SessionId,
|
||||||
snapshot::{
|
snapshot::{
|
||||||
apply_patch_set, compute_patch_set, AppliedPatchSet, InstanceContext, InstanceSnapshot,
|
apply_patch_set, compute_patch_set, AppliedPatchSet, InstanceContext,
|
||||||
PatchSet, RojoTree,
|
InstancePropertiesWithMeta, PatchSet, RojoTree,
|
||||||
},
|
},
|
||||||
snapshot_middleware::snapshot_from_vfs,
|
snapshot_middleware::snapshot_from_vfs,
|
||||||
};
|
};
|
||||||
@@ -117,7 +118,14 @@ impl ServeSession {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tree = RojoTree::new(InstanceSnapshot::new());
|
let mut tree = RojoTree::new(InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "ROOT".to_owned(),
|
||||||
|
class_name: "Folder".to_owned(),
|
||||||
|
properties: Default::default(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
@@ -195,14 +203,6 @@ impl ServeSession {
|
|||||||
self.root_project.serve_port
|
self.root_project.serve_port
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn place_id(&self) -> Option<u64> {
|
|
||||||
self.root_project.place_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn game_id(&self) -> Option<u64> {
|
|
||||||
self.root_project.game_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start_time(&self) -> Instant {
|
pub fn start_time(&self) -> Instant {
|
||||||
self.start_time
|
self.start_time
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap};
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
use rbx_dom_weak::{
|
use rbx_dom_weak::{RbxId, RbxTree, RbxValue};
|
||||||
types::{Ref, Variant},
|
|
||||||
WeakDom,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::InstanceMetadata;
|
use super::InstanceMetadata;
|
||||||
@@ -14,12 +11,11 @@ use super::InstanceMetadata;
|
|||||||
///
|
///
|
||||||
// Possible future improvements:
|
// Possible future improvements:
|
||||||
// - Use refcounted/interned strings
|
// - Use refcounted/interned strings
|
||||||
// - Replace use of Variant with a sum of Variant + borrowed value
|
// - Replace use of RbxValue with a sum of RbxValue + borrowed value
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct InstanceSnapshot {
|
pub struct InstanceSnapshot {
|
||||||
// FIXME: Don't use Option<Ref> anymore!
|
|
||||||
/// A temporary ID applied to the snapshot that's used for Ref properties.
|
/// A temporary ID applied to the snapshot that's used for Ref properties.
|
||||||
pub snapshot_id: Option<Ref>,
|
pub snapshot_id: Option<RbxId>,
|
||||||
|
|
||||||
/// Rojo-specific metadata associated with the instance.
|
/// Rojo-specific metadata associated with the instance.
|
||||||
pub metadata: InstanceMetadata,
|
pub metadata: InstanceMetadata,
|
||||||
@@ -31,7 +27,7 @@ pub struct InstanceSnapshot {
|
|||||||
pub class_name: Cow<'static, str>,
|
pub class_name: Cow<'static, str>,
|
||||||
|
|
||||||
/// All other properties of the instance, weakly-typed.
|
/// All other properties of the instance, weakly-typed.
|
||||||
pub properties: HashMap<String, Variant>,
|
pub properties: HashMap<String, RbxValue>,
|
||||||
|
|
||||||
/// The children of the instance represented as more snapshots.
|
/// The children of the instance represented as more snapshots.
|
||||||
///
|
///
|
||||||
@@ -65,16 +61,7 @@ impl InstanceSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn property<K, V>(mut self, key: K, value: V) -> Self
|
pub fn properties(self, properties: impl Into<HashMap<String, RbxValue>>) -> Self {
|
||||||
where
|
|
||||||
K: Into<String>,
|
|
||||||
V: Into<Variant>,
|
|
||||||
{
|
|
||||||
self.properties.insert(key.into(), value.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn properties(self, properties: impl Into<HashMap<String, Variant>>) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
properties: properties.into(),
|
properties: properties.into(),
|
||||||
..self
|
..self
|
||||||
@@ -88,13 +75,6 @@ impl InstanceSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot_id(self, snapshot_id: Option<Ref>) -> Self {
|
|
||||||
Self {
|
|
||||||
snapshot_id,
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn metadata(self, metadata: impl Into<InstanceMetadata>) -> Self {
|
pub fn metadata(self, metadata: impl Into<InstanceMetadata>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
metadata: metadata.into(),
|
metadata: metadata.into(),
|
||||||
@@ -102,13 +82,15 @@ impl InstanceSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_tree(tree: &WeakDom, id: Ref) -> Self {
|
pub fn from_tree(tree: &RbxTree, id: RbxId) -> Self {
|
||||||
let instance = tree.get_by_ref(id).expect("instance did not exist in tree");
|
let instance = tree
|
||||||
|
.get_instance(id)
|
||||||
|
.expect("instance did not exist in tree");
|
||||||
|
|
||||||
let children = instance
|
let children = instance
|
||||||
.children()
|
.get_children_ids()
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.cloned()
|
||||||
.map(|id| Self::from_tree(tree, id))
|
.map(|id| Self::from_tree(tree, id))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -116,7 +98,7 @@ impl InstanceSnapshot {
|
|||||||
snapshot_id: Some(id),
|
snapshot_id: Some(id),
|
||||||
metadata: InstanceMetadata::default(),
|
metadata: InstanceMetadata::default(),
|
||||||
name: Cow::Owned(instance.name.clone()),
|
name: Cow::Owned(instance.name.clone()),
|
||||||
class_name: Cow::Owned(instance.class.clone()),
|
class_name: Cow::Owned(instance.class_name.clone()),
|
||||||
properties: instance.properties.clone(),
|
properties: instance.properties.clone(),
|
||||||
children,
|
children,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{InstanceMetadata, InstanceSnapshot};
|
use super::{InstanceMetadata, InstanceSnapshot};
|
||||||
|
|
||||||
/// A set of different kinds of patches that can be applied to an WeakDom.
|
/// A set of different kinds of patches that can be applied to an RbxTree.
|
||||||
///
|
///
|
||||||
/// These patches shouldn't be persisted: there's no mechanism in place to make
|
/// These patches shouldn't be persisted: there's no mechanism in place to make
|
||||||
/// sure that another patch wasn't applied before this one that could cause a
|
/// sure that another patch wasn't applied before this one that could cause a
|
||||||
/// conflict!
|
/// conflict!
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PatchSet {
|
pub struct PatchSet {
|
||||||
pub removed_instances: Vec<Ref>,
|
pub removed_instances: Vec<RbxId>,
|
||||||
pub added_instances: Vec<PatchAdd>,
|
pub added_instances: Vec<PatchAdd>,
|
||||||
pub updated_instances: Vec<PatchUpdate>,
|
pub updated_instances: Vec<PatchUpdate>,
|
||||||
}
|
}
|
||||||
@@ -32,20 +32,20 @@ impl<'a> PatchSet {
|
|||||||
/// A patch containing an instance that was added to the tree.
|
/// A patch containing an instance that was added to the tree.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PatchAdd {
|
pub struct PatchAdd {
|
||||||
pub parent_id: Ref,
|
pub parent_id: RbxId,
|
||||||
pub instance: InstanceSnapshot,
|
pub instance: InstanceSnapshot,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A patch indicating that properties of an instance changed.
|
/// A patch indicating that properties of an instance changed.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PatchUpdate {
|
pub struct PatchUpdate {
|
||||||
pub id: Ref,
|
pub id: RbxId,
|
||||||
pub changed_name: Option<String>,
|
pub changed_name: Option<String>,
|
||||||
pub changed_class_name: Option<String>,
|
pub changed_class_name: Option<String>,
|
||||||
|
|
||||||
/// Contains all changed properties. If a property is assigned to `None`,
|
/// Contains all changed properties. If a property is assigned to `None`,
|
||||||
/// then that property has been removed.
|
/// then that property has been removed.
|
||||||
pub changed_properties: HashMap<String, Option<Variant>>,
|
pub changed_properties: HashMap<String, Option<RbxValue>>,
|
||||||
|
|
||||||
/// Changed Rojo-specific metadata, if any of it changed.
|
/// Changed Rojo-specific metadata, if any of it changed.
|
||||||
pub changed_metadata: Option<InstanceMetadata>,
|
pub changed_metadata: Option<InstanceMetadata>,
|
||||||
@@ -63,8 +63,8 @@ pub struct PatchUpdate {
|
|||||||
// current values in all fields.
|
// current values in all fields.
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct AppliedPatchSet {
|
pub struct AppliedPatchSet {
|
||||||
pub removed: Vec<Ref>,
|
pub removed: Vec<RbxId>,
|
||||||
pub added: Vec<Ref>,
|
pub added: Vec<RbxId>,
|
||||||
pub updated: Vec<AppliedPatchUpdate>,
|
pub updated: Vec<AppliedPatchUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,17 +80,17 @@ impl AppliedPatchSet {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct AppliedPatchUpdate {
|
pub struct AppliedPatchUpdate {
|
||||||
pub id: Ref,
|
pub id: RbxId,
|
||||||
|
|
||||||
// TODO: Store previous values in order to detect application conflicts
|
// TODO: Store previous values in order to detect application conflicts
|
||||||
pub changed_name: Option<String>,
|
pub changed_name: Option<String>,
|
||||||
pub changed_class_name: Option<String>,
|
pub changed_class_name: Option<String>,
|
||||||
pub changed_properties: HashMap<String, Option<Variant>>,
|
pub changed_properties: HashMap<String, Option<RbxValue>>,
|
||||||
pub changed_metadata: Option<InstanceMetadata>,
|
pub changed_metadata: Option<InstanceMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppliedPatchUpdate {
|
impl AppliedPatchUpdate {
|
||||||
pub fn new(id: Ref) -> Self {
|
pub fn new(id: RbxId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
changed_name: None,
|
changed_name: None,
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxInstanceProperties, RbxValue};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate},
|
patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate},
|
||||||
InstanceSnapshot, RojoTree,
|
InstancePropertiesWithMeta, InstanceSnapshot, RojoTree,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Consumes the input `PatchSet`, applying all of its prescribed changes to the
|
/// Consumes the input `PatchSet`, applying all of its prescribed changes to the
|
||||||
@@ -37,7 +37,7 @@ pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatch
|
|||||||
struct PatchApplyContext {
|
struct PatchApplyContext {
|
||||||
/// A map from transient snapshot IDs (generated by snapshot middleware) to
|
/// A map from transient snapshot IDs (generated by snapshot middleware) to
|
||||||
/// instance IDs in the actual tree. These are both the same data type so
|
/// instance IDs in the actual tree. These are both the same data type so
|
||||||
/// that they fit into the same `Variant::Ref` type.
|
/// that they fit into the same `RbxValue::Ref` type.
|
||||||
///
|
///
|
||||||
/// At this point in the patch process, IDs in instance properties have been
|
/// At this point in the patch process, IDs in instance properties have been
|
||||||
/// partially translated from 'snapshot space' into 'tree space' by the
|
/// partially translated from 'snapshot space' into 'tree space' by the
|
||||||
@@ -53,7 +53,7 @@ struct PatchApplyContext {
|
|||||||
/// #2 should not occur in well-formed projects, but is indistinguishable
|
/// #2 should not occur in well-formed projects, but is indistinguishable
|
||||||
/// from #1 right now. It could happen if two model files try to reference
|
/// from #1 right now. It could happen if two model files try to reference
|
||||||
/// eachother.
|
/// eachother.
|
||||||
snapshot_id_to_instance_id: HashMap<Ref, Ref>,
|
snapshot_id_to_instance_id: HashMap<RbxId, RbxId>,
|
||||||
|
|
||||||
/// The properties of instances added by the current `PatchSet`.
|
/// The properties of instances added by the current `PatchSet`.
|
||||||
///
|
///
|
||||||
@@ -68,7 +68,7 @@ struct PatchApplyContext {
|
|||||||
///
|
///
|
||||||
/// This doesn't affect updated instances, since they're always applied
|
/// This doesn't affect updated instances, since they're always applied
|
||||||
/// after we've added all the instances from the patch.
|
/// after we've added all the instances from the patch.
|
||||||
added_instance_properties: HashMap<Ref, HashMap<String, Variant>>,
|
added_instance_properties: HashMap<RbxId, HashMap<String, RbxValue>>,
|
||||||
|
|
||||||
/// The current applied patch result, describing changes made to the tree.
|
/// The current applied patch result, describing changes made to the tree.
|
||||||
applied_patch_set: AppliedPatchSet,
|
applied_patch_set: AppliedPatchSet,
|
||||||
@@ -93,10 +93,11 @@ fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -
|
|||||||
.expect("Invalid instance ID in deferred property map");
|
.expect("Invalid instance ID in deferred property map");
|
||||||
|
|
||||||
for (key, mut property_value) in properties {
|
for (key, mut property_value) in properties {
|
||||||
if let Variant::Ref(referent) = property_value {
|
if let RbxValue::Ref { value: Some(id) } = property_value {
|
||||||
if let Some(&instance_referent) = context.snapshot_id_to_instance_id.get(&referent)
|
if let Some(&instance_id) = context.snapshot_id_to_instance_id.get(&id) {
|
||||||
{
|
property_value = RbxValue::Ref {
|
||||||
property_value = Variant::Ref(instance_referent);
|
value: Some(instance_id),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,40 +108,50 @@ fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -
|
|||||||
context.applied_patch_set
|
context.applied_patch_set
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_remove_instance(context: &mut PatchApplyContext, tree: &mut RojoTree, removed_id: Ref) {
|
fn apply_remove_instance(context: &mut PatchApplyContext, tree: &mut RojoTree, removed_id: RbxId) {
|
||||||
tree.remove(removed_id);
|
match tree.remove_instance(removed_id) {
|
||||||
context.applied_patch_set.removed.push(removed_id);
|
Some(_) => context.applied_patch_set.removed.push(removed_id),
|
||||||
|
None => {
|
||||||
|
log::warn!(
|
||||||
|
"Patch misapplication: Tried to remove instance {} but it did not exist.",
|
||||||
|
removed_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_add_child(
|
fn apply_add_child(
|
||||||
context: &mut PatchApplyContext,
|
context: &mut PatchApplyContext,
|
||||||
tree: &mut RojoTree,
|
tree: &mut RojoTree,
|
||||||
parent_id: Ref,
|
parent_id: RbxId,
|
||||||
snapshot: InstanceSnapshot,
|
snapshot: InstanceSnapshot,
|
||||||
) {
|
) {
|
||||||
let snapshot_id = snapshot.snapshot_id;
|
let properties = InstancePropertiesWithMeta {
|
||||||
let properties = snapshot.properties;
|
properties: RbxInstanceProperties {
|
||||||
let children = snapshot.children;
|
name: snapshot.name.into_owned(),
|
||||||
|
class_name: snapshot.class_name.into_owned(),
|
||||||
|
|
||||||
// Property application is deferred until after all children
|
// Property assignment is deferred until after we know about all
|
||||||
// are constructed. This helps apply referents correctly.
|
// instances in this patch. See `PatchApplyContext` for details.
|
||||||
let remaining_snapshot = InstanceSnapshot::new()
|
properties: HashMap::new(),
|
||||||
.name(snapshot.name)
|
},
|
||||||
.class_name(snapshot.class_name)
|
metadata: snapshot.metadata,
|
||||||
.metadata(snapshot.metadata)
|
};
|
||||||
.snapshot_id(snapshot.snapshot_id);
|
|
||||||
|
let id = tree.insert_instance(properties, parent_id);
|
||||||
|
|
||||||
let id = tree.insert_instance(parent_id, remaining_snapshot);
|
|
||||||
context.applied_patch_set.added.push(id);
|
context.applied_patch_set.added.push(id);
|
||||||
|
|
||||||
context.added_instance_properties.insert(id, properties);
|
context
|
||||||
|
.added_instance_properties
|
||||||
|
.insert(id, snapshot.properties);
|
||||||
|
|
||||||
if let Some(snapshot_id) = snapshot_id {
|
if let Some(snapshot_id) = snapshot.snapshot_id {
|
||||||
context.snapshot_id_to_instance_id.insert(snapshot_id, id);
|
context.snapshot_id_to_instance_id.insert(snapshot_id, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in children {
|
for child_snapshot in snapshot.children {
|
||||||
apply_add_child(context, tree, id, child);
|
apply_add_child(context, tree, id, child_snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +167,7 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
|
|||||||
Some(instance) => instance,
|
Some(instance) => instance,
|
||||||
None => {
|
None => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Patch misapplication: Instance {:?}, referred to by update patch, did not exist.",
|
"Patch misapplication: Instance {}, referred to by update patch, did not exist.",
|
||||||
patch.id
|
patch.id
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -178,24 +189,23 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
|
|||||||
// Ref values need to be potentially rewritten from snapshot IDs to
|
// Ref values need to be potentially rewritten from snapshot IDs to
|
||||||
// instance IDs if they referred to an instance that was created as
|
// instance IDs if they referred to an instance that was created as
|
||||||
// part of this patch.
|
// part of this patch.
|
||||||
Some(Variant::Ref(referent)) => {
|
Some(RbxValue::Ref { value: Some(id) }) => {
|
||||||
if referent.is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If our ID is not found in this map, then it either refers to
|
// If our ID is not found in this map, then it either refers to
|
||||||
// an existing instance NOT added by this patch, or there was an
|
// an existing instance NOT added by this patch, or there was an
|
||||||
// error. See `PatchApplyContext::snapshot_id_to_instance_id`
|
// error. See `PatchApplyContext::snapshot_id_to_instance_id`
|
||||||
// for more info.
|
// for more info.
|
||||||
let new_referent = context
|
let new_id = context
|
||||||
.snapshot_id_to_instance_id
|
.snapshot_id_to_instance_id
|
||||||
.get(&referent)
|
.get(&id)
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(referent);
|
.unwrap_or(id);
|
||||||
|
|
||||||
instance
|
instance.properties_mut().insert(
|
||||||
.properties_mut()
|
key.clone(),
|
||||||
.insert(key.clone(), Variant::Ref(new_referent));
|
RbxValue::Ref {
|
||||||
|
value: Some(new_id),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Some(ref value) => {
|
Some(ref value) => {
|
||||||
instance.properties_mut().insert(key.clone(), value.clone());
|
instance.properties_mut().insert(key.clone(), value.clone());
|
||||||
@@ -215,10 +225,10 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use rbx_dom_weak::types::Variant;
|
use rbx_dom_weak::RbxValue;
|
||||||
|
|
||||||
use super::super::PatchAdd;
|
use super::super::PatchAdd;
|
||||||
|
|
||||||
@@ -226,7 +236,14 @@ mod test {
|
|||||||
fn add_from_empty() {
|
fn add_from_empty() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
let mut tree = RojoTree::new(InstanceSnapshot::new());
|
let mut tree = RojoTree::new(InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "Folder".to_owned(),
|
||||||
|
class_name: "Folder".to_owned(),
|
||||||
|
properties: HashMap::new(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
@@ -236,7 +253,7 @@ mod test {
|
|||||||
name: Cow::Borrowed("Foo"),
|
name: Cow::Borrowed("Foo"),
|
||||||
class_name: Cow::Borrowed("Bar"),
|
class_name: Cow::Borrowed("Bar"),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
"Baz".to_owned() => Variant::Int32(5),
|
"Baz".to_owned() => RbxValue::Int32 { value: 5 },
|
||||||
},
|
},
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -265,14 +282,18 @@ mod test {
|
|||||||
fn update_existing() {
|
fn update_existing() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
let mut tree = RojoTree::new(
|
let mut tree = RojoTree::new(InstancePropertiesWithMeta {
|
||||||
InstanceSnapshot::new()
|
properties: RbxInstanceProperties {
|
||||||
.class_name("OldClassName")
|
name: "OldName".to_owned(),
|
||||||
.name("OldName")
|
class_name: "OldClassName".to_owned(),
|
||||||
.property("Foo", 7i32)
|
properties: hashmap! {
|
||||||
.property("Bar", 3i32)
|
"Foo".to_owned() => RbxValue::Int32 { value: 7 },
|
||||||
.property("Unchanged", -5i32),
|
"Bar".to_owned() => RbxValue::Int32 { value: 3 },
|
||||||
);
|
"Unchanged".to_owned() => RbxValue::Int32 { value: -5 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
@@ -282,13 +303,13 @@ mod test {
|
|||||||
changed_class_name: Some("NewClassName".to_owned()),
|
changed_class_name: Some("NewClassName".to_owned()),
|
||||||
changed_properties: hashmap! {
|
changed_properties: hashmap! {
|
||||||
// The value of Foo has changed
|
// The value of Foo has changed
|
||||||
"Foo".to_owned() => Some(Variant::Int32(8)),
|
"Foo".to_owned() => Some(RbxValue::Int32 { value: 8 }),
|
||||||
|
|
||||||
// Bar has been deleted
|
// Bar has been deleted
|
||||||
"Bar".to_owned() => None,
|
"Bar".to_owned() => None,
|
||||||
|
|
||||||
// Baz has been added
|
// Baz has been added
|
||||||
"Baz".to_owned() => Some(Variant::Int32(10)),
|
"Baz".to_owned() => Some(RbxValue::Int32 { value: 10 }),
|
||||||
},
|
},
|
||||||
changed_metadata: None,
|
changed_metadata: None,
|
||||||
};
|
};
|
||||||
@@ -301,9 +322,9 @@ mod test {
|
|||||||
apply_patch_set(&mut tree, patch_set);
|
apply_patch_set(&mut tree, patch_set);
|
||||||
|
|
||||||
let expected_properties = hashmap! {
|
let expected_properties = hashmap! {
|
||||||
"Foo".to_owned() => Variant::Int32(8),
|
"Foo".to_owned() => RbxValue::Int32 { value: 8 },
|
||||||
"Baz".to_owned() => Variant::Int32(10),
|
"Baz".to_owned() => RbxValue::Int32 { value: 10 },
|
||||||
"Unchanged".to_owned() => Variant::Int32(-5),
|
"Unchanged".to_owned() => RbxValue::Int32 { value: -5 },
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_instance = tree.get_instance(root_id).unwrap();
|
let root_instance = tree.get_instance(root_id).unwrap();
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
patch::{PatchAdd, PatchSet, PatchUpdate},
|
patch::{PatchAdd, PatchSet, PatchUpdate},
|
||||||
InstanceSnapshot, InstanceWithMeta, RojoTree,
|
InstanceSnapshot, InstanceWithMeta, RojoTree,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn compute_patch_set(snapshot: &InstanceSnapshot, tree: &RojoTree, id: Ref) -> PatchSet {
|
pub fn compute_patch_set(snapshot: &InstanceSnapshot, tree: &RojoTree, id: RbxId) -> PatchSet {
|
||||||
let mut patch_set = PatchSet::new();
|
let mut patch_set = PatchSet::new();
|
||||||
let mut context = ComputePatchContext::default();
|
let mut context = ComputePatchContext::default();
|
||||||
|
|
||||||
@@ -26,15 +26,17 @@ pub fn compute_patch_set(snapshot: &InstanceSnapshot, tree: &RojoTree, id: Ref)
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ComputePatchContext {
|
struct ComputePatchContext {
|
||||||
snapshot_id_to_instance_id: HashMap<Ref, Ref>,
|
snapshot_id_to_instance_id: HashMap<RbxId, RbxId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rewrite_refs_in_updates(context: &ComputePatchContext, updates: &mut [PatchUpdate]) {
|
fn rewrite_refs_in_updates(context: &ComputePatchContext, updates: &mut [PatchUpdate]) {
|
||||||
for update in updates {
|
for update in updates {
|
||||||
for property_value in update.changed_properties.values_mut() {
|
for property_value in update.changed_properties.values_mut() {
|
||||||
if let Some(Variant::Ref(referent)) = property_value {
|
if let Some(RbxValue::Ref { value: Some(id) }) = property_value {
|
||||||
if let Some(&instance_ref) = context.snapshot_id_to_instance_id.get(referent) {
|
if let Some(&instance_id) = context.snapshot_id_to_instance_id.get(id) {
|
||||||
*property_value = Some(Variant::Ref(instance_ref));
|
*property_value = Some(RbxValue::Ref {
|
||||||
|
value: Some(instance_id),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,9 +51,11 @@ fn rewrite_refs_in_additions(context: &ComputePatchContext, additions: &mut [Pat
|
|||||||
|
|
||||||
fn rewrite_refs_in_snapshot(context: &ComputePatchContext, snapshot: &mut InstanceSnapshot) {
|
fn rewrite_refs_in_snapshot(context: &ComputePatchContext, snapshot: &mut InstanceSnapshot) {
|
||||||
for property_value in snapshot.properties.values_mut() {
|
for property_value in snapshot.properties.values_mut() {
|
||||||
if let Variant::Ref(referent) = property_value {
|
if let RbxValue::Ref { value: Some(id) } = property_value {
|
||||||
if let Some(&instance_referent) = context.snapshot_id_to_instance_id.get(referent) {
|
if let Some(&instance_id) = context.snapshot_id_to_instance_id.get(id) {
|
||||||
*property_value = Variant::Ref(instance_referent);
|
*property_value = RbxValue::Ref {
|
||||||
|
value: Some(instance_id),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,7 +69,7 @@ fn compute_patch_set_internal(
|
|||||||
context: &mut ComputePatchContext,
|
context: &mut ComputePatchContext,
|
||||||
snapshot: &InstanceSnapshot,
|
snapshot: &InstanceSnapshot,
|
||||||
tree: &RojoTree,
|
tree: &RojoTree,
|
||||||
id: Ref,
|
id: RbxId,
|
||||||
patch_set: &mut PatchSet,
|
patch_set: &mut PatchSet,
|
||||||
) {
|
) {
|
||||||
if let Some(snapshot_id) = snapshot.snapshot_id {
|
if let Some(snapshot_id) = snapshot.snapshot_id {
|
||||||
@@ -150,7 +154,7 @@ fn compute_children_patches(
|
|||||||
context: &mut ComputePatchContext,
|
context: &mut ComputePatchContext,
|
||||||
snapshot: &InstanceSnapshot,
|
snapshot: &InstanceSnapshot,
|
||||||
tree: &RojoTree,
|
tree: &RojoTree,
|
||||||
id: Ref,
|
id: RbxId,
|
||||||
patch_set: &mut PatchSet,
|
patch_set: &mut PatchSet,
|
||||||
) {
|
) {
|
||||||
let instance = tree
|
let instance = tree
|
||||||
@@ -220,6 +224,9 @@ mod test {
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
|
use rbx_dom_weak::RbxInstanceProperties;
|
||||||
|
|
||||||
|
use super::super::InstancePropertiesWithMeta;
|
||||||
|
|
||||||
/// This test makes sure that rewriting refs in instance update patches to
|
/// This test makes sure that rewriting refs in instance update patches to
|
||||||
/// instances that already exists works. We should be able to correlate the
|
/// instances that already exists works. We should be able to correlate the
|
||||||
@@ -227,17 +234,26 @@ mod test {
|
|||||||
/// value before returning from compute_patch_set.
|
/// value before returning from compute_patch_set.
|
||||||
#[test]
|
#[test]
|
||||||
fn rewrite_ref_existing_instance_update() {
|
fn rewrite_ref_existing_instance_update() {
|
||||||
let tree = RojoTree::new(InstanceSnapshot::new().name("foo").class_name("foo"));
|
let tree = RojoTree::new(InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "foo".to_owned(),
|
||||||
|
class_name: "foo".to_owned(),
|
||||||
|
properties: HashMap::new(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
// This snapshot should be identical to the existing tree except for the
|
// This snapshot should be identical to the existing tree except for the
|
||||||
// addition of a prop named Self, which is a self-referential Ref.
|
// addition of a prop named Self, which is a self-referential Ref.
|
||||||
let snapshot_id = Ref::new();
|
let snapshot_id = RbxId::new();
|
||||||
let snapshot = InstanceSnapshot {
|
let snapshot = InstanceSnapshot {
|
||||||
snapshot_id: Some(snapshot_id),
|
snapshot_id: Some(snapshot_id),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
"Self".to_owned() => Variant::Ref(snapshot_id),
|
"Self".to_owned() => RbxValue::Ref {
|
||||||
|
value: Some(snapshot_id),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
metadata: Default::default(),
|
metadata: Default::default(),
|
||||||
@@ -254,7 +270,9 @@ mod test {
|
|||||||
changed_name: None,
|
changed_name: None,
|
||||||
changed_class_name: None,
|
changed_class_name: None,
|
||||||
changed_properties: hashmap! {
|
changed_properties: hashmap! {
|
||||||
"Self".to_owned() => Some(Variant::Ref(root_id)),
|
"Self".to_owned() => Some(RbxValue::Ref {
|
||||||
|
value: Some(root_id),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
changed_metadata: None,
|
changed_metadata: None,
|
||||||
}],
|
}],
|
||||||
@@ -270,17 +288,26 @@ mod test {
|
|||||||
/// one.
|
/// one.
|
||||||
#[test]
|
#[test]
|
||||||
fn rewrite_ref_existing_instance_addition() {
|
fn rewrite_ref_existing_instance_addition() {
|
||||||
let tree = RojoTree::new(InstanceSnapshot::new().name("foo").class_name("foo"));
|
let tree = RojoTree::new(InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "foo".to_owned(),
|
||||||
|
class_name: "foo".to_owned(),
|
||||||
|
properties: HashMap::new(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
// This patch describes the existing instance with a new child added.
|
// This patch describes the existing instance with a new child added.
|
||||||
let snapshot_id = Ref::new();
|
let snapshot_id = RbxId::new();
|
||||||
let snapshot = InstanceSnapshot {
|
let snapshot = InstanceSnapshot {
|
||||||
snapshot_id: Some(snapshot_id),
|
snapshot_id: Some(snapshot_id),
|
||||||
children: vec![InstanceSnapshot {
|
children: vec![InstanceSnapshot {
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
"Self".to_owned() => Variant::Ref(snapshot_id),
|
"Self".to_owned() => RbxValue::Ref {
|
||||||
|
value: Some(snapshot_id),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
@@ -305,7 +332,9 @@ mod test {
|
|||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
metadata: Default::default(),
|
metadata: Default::default(),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
"Self".to_owned() => Variant::Ref(root_id),
|
"Self".to_owned() => RbxValue::Ref {
|
||||||
|
value: Some(root_id),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
name: Cow::Borrowed("child"),
|
name: Cow::Borrowed("child"),
|
||||||
class_name: Cow::Borrowed("child"),
|
class_name: Cow::Borrowed("child"),
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use insta::assert_yaml_snapshot;
|
use insta::assert_yaml_snapshot;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
|
use rbx_dom_weak::{RbxInstanceProperties, RbxValue};
|
||||||
|
|
||||||
use rojo_insta_ext::RedactionMap;
|
use rojo_insta_ext::RedactionMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
snapshot::{apply_patch_set, InstanceSnapshot, PatchSet, PatchUpdate, RojoTree},
|
snapshot::{apply_patch_set, InstancePropertiesWithMeta, PatchSet, PatchUpdate, RojoTree},
|
||||||
tree_view::{intern_tree, view_tree},
|
tree_view::{intern_tree, view_tree},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,7 +49,9 @@ fn add_property() {
|
|||||||
changed_name: None,
|
changed_name: None,
|
||||||
changed_class_name: None,
|
changed_class_name: None,
|
||||||
changed_properties: hashmap! {
|
changed_properties: hashmap! {
|
||||||
"Foo".to_owned() => Some("Value of Foo".into()),
|
"Foo".to_owned() => Some(RbxValue::String {
|
||||||
|
value: "Value of Foo".to_owned(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
changed_metadata: None,
|
changed_metadata: None,
|
||||||
}],
|
}],
|
||||||
@@ -75,9 +78,12 @@ fn remove_property() {
|
|||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
let mut root_instance = tree.get_instance_mut(root_id).unwrap();
|
let mut root_instance = tree.get_instance_mut(root_id).unwrap();
|
||||||
|
|
||||||
root_instance
|
root_instance.properties_mut().insert(
|
||||||
.properties_mut()
|
"Foo".to_owned(),
|
||||||
.insert("Foo".to_owned(), "Should be removed".into());
|
RbxValue::String {
|
||||||
|
value: "Should be removed".to_owned(),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree_view = view_tree(&tree, &mut redactions);
|
let tree_view = view_tree(&tree, &mut redactions);
|
||||||
@@ -106,5 +112,12 @@ fn remove_property() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn empty_tree() -> RojoTree {
|
fn empty_tree() -> RojoTree {
|
||||||
RojoTree::new(InstanceSnapshot::new().name("ROOT").class_name("ROOT"))
|
RojoTree::new(InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "ROOT".to_owned(),
|
||||||
|
class_name: "ROOT".to_owned(),
|
||||||
|
properties: Default::default(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ use std::borrow::Cow;
|
|||||||
|
|
||||||
use insta::assert_yaml_snapshot;
|
use insta::assert_yaml_snapshot;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
|
use rbx_dom_weak::{RbxInstanceProperties, RbxValue};
|
||||||
|
|
||||||
use rojo_insta_ext::RedactionMap;
|
use rojo_insta_ext::RedactionMap;
|
||||||
|
|
||||||
use crate::snapshot::{compute_patch_set, InstanceSnapshot, RojoTree};
|
use crate::snapshot::{compute_patch_set, InstancePropertiesWithMeta, InstanceSnapshot, RojoTree};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_name_and_class_name() {
|
fn set_name_and_class_name() {
|
||||||
@@ -42,7 +43,9 @@ fn set_property() {
|
|||||||
name: Cow::Borrowed("ROOT"),
|
name: Cow::Borrowed("ROOT"),
|
||||||
class_name: Cow::Borrowed("ROOT"),
|
class_name: Cow::Borrowed("ROOT"),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
"PropertyName".to_owned() => "Hello, world!".into(),
|
"PropertyName".to_owned() => RbxValue::String {
|
||||||
|
value: "Hello, world!".to_owned(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -65,7 +68,9 @@ fn remove_property() {
|
|||||||
let mut root_instance = tree.get_instance_mut(root_id).unwrap();
|
let mut root_instance = tree.get_instance_mut(root_id).unwrap();
|
||||||
root_instance.properties_mut().insert(
|
root_instance.properties_mut().insert(
|
||||||
"Foo".to_owned(),
|
"Foo".to_owned(),
|
||||||
"This should be removed by the patch.".into(),
|
RbxValue::String {
|
||||||
|
value: "This should be removed by the patch.".to_owned(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +128,15 @@ fn remove_child() {
|
|||||||
{
|
{
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
let new_id = tree.insert_instance(
|
let new_id = tree.insert_instance(
|
||||||
|
InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "Should not appear in snapshot".to_owned(),
|
||||||
|
class_name: "Folder".to_owned(),
|
||||||
|
properties: Default::default(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
},
|
||||||
root_id,
|
root_id,
|
||||||
InstanceSnapshot::new().name("Should not appear in snapshot"),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
redactions.intern(new_id);
|
redactions.intern(new_id);
|
||||||
@@ -146,5 +158,12 @@ fn remove_child() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn empty_tree() -> RojoTree {
|
fn empty_tree() -> RojoTree {
|
||||||
RojoTree::new(InstanceSnapshot::new().name("ROOT").class_name("ROOT"))
|
RojoTree::new(InstancePropertiesWithMeta {
|
||||||
|
properties: RbxInstanceProperties {
|
||||||
|
name: "ROOT".to_owned(),
|
||||||
|
class_name: "ROOT".to_owned(),
|
||||||
|
properties: Default::default(),
|
||||||
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,26 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::HashMap,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use rbx_dom_weak::{
|
use rbx_dom_weak::{Descendants, RbxId, RbxInstance, RbxInstanceProperties, RbxTree, RbxValue};
|
||||||
types::{Ref, Variant},
|
|
||||||
Instance, InstanceBuilder, WeakDom,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::multimap::MultiMap;
|
use crate::multimap::MultiMap;
|
||||||
|
|
||||||
use super::{InstanceMetadata, InstanceSnapshot};
|
use super::InstanceMetadata;
|
||||||
|
|
||||||
/// An expanded variant of rbx_dom_weak's `WeakDom` that tracks additional
|
/// An expanded variant of rbx_dom_weak's `RbxTree` that tracks additional
|
||||||
/// metadata per instance that's Rojo-specific.
|
/// metadata per instance that's Rojo-specific.
|
||||||
///
|
///
|
||||||
/// This tree is also optimized for doing fast incremental updates and patches.
|
/// This tree is also optimized for doing fast incremental updates and patches.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RojoTree {
|
pub struct RojoTree {
|
||||||
/// Contains the instances without their Rojo-specific metadata.
|
/// Contains the instances without their Rojo-specific metadata.
|
||||||
inner: WeakDom,
|
inner: RbxTree,
|
||||||
|
|
||||||
/// Metadata associated with each instance that is kept up-to-date with the
|
/// Metadata associated with each instance that is kept up-to-date with the
|
||||||
/// set of actual instances.
|
/// set of actual instances.
|
||||||
metadata_map: HashMap<Ref, InstanceMetadata>,
|
metadata_map: HashMap<RbxId, InstanceMetadata>,
|
||||||
|
|
||||||
/// A multimap from source paths to all of the root instances that were
|
/// A multimap from source paths to all of the root instances that were
|
||||||
/// constructed from that path.
|
/// constructed from that path.
|
||||||
@@ -32,42 +29,31 @@ pub struct RojoTree {
|
|||||||
/// value portion of the map is also a set in order to support the same path
|
/// value portion of the map is also a set in order to support the same path
|
||||||
/// appearing multiple times in the same Rojo project. This is sometimes
|
/// appearing multiple times in the same Rojo project. This is sometimes
|
||||||
/// called "path aliasing" in various Rojo documentation.
|
/// called "path aliasing" in various Rojo documentation.
|
||||||
path_to_ids: MultiMap<PathBuf, Ref>,
|
path_to_ids: MultiMap<PathBuf, RbxId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RojoTree {
|
impl RojoTree {
|
||||||
pub fn new(snapshot: InstanceSnapshot) -> RojoTree {
|
pub fn new(root: InstancePropertiesWithMeta) -> RojoTree {
|
||||||
let root_builder = InstanceBuilder::new(snapshot.class_name.to_owned())
|
|
||||||
.with_name(snapshot.name.to_owned())
|
|
||||||
.with_properties(snapshot.properties);
|
|
||||||
|
|
||||||
let mut tree = RojoTree {
|
let mut tree = RojoTree {
|
||||||
inner: WeakDom::new(root_builder),
|
inner: RbxTree::new(root.properties),
|
||||||
metadata_map: HashMap::new(),
|
metadata_map: HashMap::new(),
|
||||||
path_to_ids: MultiMap::new(),
|
path_to_ids: MultiMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_ref = tree.inner.root_ref();
|
tree.insert_metadata(tree.inner.get_root_id(), root.metadata);
|
||||||
|
|
||||||
tree.insert_metadata(root_ref, snapshot.metadata);
|
|
||||||
|
|
||||||
for child in snapshot.children {
|
|
||||||
tree.insert_instance(root_ref, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
tree
|
tree
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &WeakDom {
|
pub fn inner(&self) -> &RbxTree {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_root_id(&self) -> Ref {
|
pub fn get_root_id(&self) -> RbxId {
|
||||||
self.inner.root_ref()
|
self.inner.get_root_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_instance(&self, id: Ref) -> Option<InstanceWithMeta> {
|
pub fn get_instance(&self, id: RbxId) -> Option<InstanceWithMeta> {
|
||||||
if let Some(instance) = self.inner.get_by_ref(id) {
|
if let Some(instance) = self.inner.get_instance(id) {
|
||||||
let metadata = self.metadata_map.get(&id).unwrap();
|
let metadata = self.metadata_map.get(&id).unwrap();
|
||||||
|
|
||||||
Some(InstanceWithMeta { instance, metadata })
|
Some(InstanceWithMeta { instance, metadata })
|
||||||
@@ -76,8 +62,8 @@ impl RojoTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_instance_mut(&mut self, id: Ref) -> Option<InstanceWithMetaMut> {
|
pub fn get_instance_mut(&mut self, id: RbxId) -> Option<InstanceWithMetaMut> {
|
||||||
if let Some(instance) = self.inner.get_by_ref_mut(id) {
|
if let Some(instance) = self.inner.get_instance_mut(id) {
|
||||||
let metadata = self.metadata_map.get_mut(&id).unwrap();
|
let metadata = self.metadata_map.get_mut(&id).unwrap();
|
||||||
|
|
||||||
Some(InstanceWithMetaMut { instance, metadata })
|
Some(InstanceWithMetaMut { instance, metadata })
|
||||||
@@ -86,38 +72,38 @@ impl RojoTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_instance(&mut self, parent_ref: Ref, snapshot: InstanceSnapshot) -> Ref {
|
pub fn insert_instance(
|
||||||
let builder = InstanceBuilder::new(snapshot.class_name.to_owned())
|
&mut self,
|
||||||
.with_name(snapshot.name.to_owned())
|
properties: InstancePropertiesWithMeta,
|
||||||
.with_properties(snapshot.properties);
|
parent_id: RbxId,
|
||||||
|
) -> RbxId {
|
||||||
let referent = self.inner.insert(parent_ref, builder);
|
let id = self.inner.insert_instance(properties.properties, parent_id);
|
||||||
self.insert_metadata(referent, snapshot.metadata);
|
self.insert_metadata(id, properties.metadata);
|
||||||
|
id
|
||||||
for child in snapshot.children {
|
|
||||||
self.insert_instance(referent, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
referent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, id: Ref) {
|
pub fn remove_instance(&mut self, id: RbxId) -> Option<RojoTree> {
|
||||||
let mut to_move = VecDeque::new();
|
if let Some(inner) = self.inner.remove_instance(id) {
|
||||||
to_move.push_back(id);
|
let mut metadata_map = HashMap::new();
|
||||||
|
let mut path_to_ids = MultiMap::new();
|
||||||
|
|
||||||
while let Some(id) = to_move.pop_front() {
|
self.move_metadata(id, &mut metadata_map, &mut path_to_ids);
|
||||||
self.remove_metadata(id);
|
for instance in inner.descendants(id) {
|
||||||
|
self.move_metadata(instance.get_id(), &mut metadata_map, &mut path_to_ids);
|
||||||
if let Some(instance) = self.inner.get_by_ref(id) {
|
|
||||||
to_move.extend(instance.children().iter().copied());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.inner.destroy(id);
|
Some(RojoTree {
|
||||||
|
inner,
|
||||||
|
metadata_map,
|
||||||
|
path_to_ids,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the metadata associated with the given instance ID.
|
/// Replaces the metadata associated with the given instance ID.
|
||||||
pub fn update_metadata(&mut self, id: Ref, metadata: InstanceMetadata) {
|
pub fn update_metadata(&mut self, id: RbxId, metadata: InstanceMetadata) {
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
|
||||||
match self.metadata_map.entry(id) {
|
match self.metadata_map.entry(id) {
|
||||||
@@ -145,22 +131,22 @@ impl RojoTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn descendants(&self, id: Ref) -> RojoDescendants<'_> {
|
pub fn descendants(&self, id: RbxId) -> RojoDescendants<'_> {
|
||||||
let mut queue = VecDeque::new();
|
RojoDescendants {
|
||||||
queue.push_back(id);
|
inner: self.inner.descendants(id),
|
||||||
|
tree: self,
|
||||||
RojoDescendants { queue, tree: self }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ids_at_path(&self, path: &Path) -> &[Ref] {
|
pub fn get_ids_at_path(&self, path: &Path) -> &[RbxId] {
|
||||||
self.path_to_ids.get(path)
|
self.path_to_ids.get(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_metadata(&self, id: Ref) -> Option<&InstanceMetadata> {
|
pub fn get_metadata(&self, id: RbxId) -> Option<&InstanceMetadata> {
|
||||||
self.metadata_map.get(&id)
|
self.metadata_map.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_metadata(&mut self, id: Ref, metadata: InstanceMetadata) {
|
fn insert_metadata(&mut self, id: RbxId, metadata: InstanceMetadata) {
|
||||||
for path in &metadata.relevant_paths {
|
for path in &metadata.relevant_paths {
|
||||||
self.path_to_ids.insert(path.clone(), id);
|
self.path_to_ids.insert(path.clone(), id);
|
||||||
}
|
}
|
||||||
@@ -170,17 +156,25 @@ impl RojoTree {
|
|||||||
|
|
||||||
/// Moves the Rojo metadata from the instance with the given ID from this
|
/// Moves the Rojo metadata from the instance with the given ID from this
|
||||||
/// tree into some loose maps.
|
/// tree into some loose maps.
|
||||||
fn remove_metadata(&mut self, id: Ref) {
|
fn move_metadata(
|
||||||
|
&mut self,
|
||||||
|
id: RbxId,
|
||||||
|
metadata_map: &mut HashMap<RbxId, InstanceMetadata>,
|
||||||
|
path_to_ids: &mut MultiMap<PathBuf, RbxId>,
|
||||||
|
) {
|
||||||
let metadata = self.metadata_map.remove(&id).unwrap();
|
let metadata = self.metadata_map.remove(&id).unwrap();
|
||||||
|
|
||||||
for path in &metadata.relevant_paths {
|
for path in &metadata.relevant_paths {
|
||||||
self.path_to_ids.remove(path, id);
|
self.path_to_ids.remove(path, id);
|
||||||
|
path_to_ids.insert(path.clone(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metadata_map.insert(id, metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RojoDescendants<'a> {
|
pub struct RojoDescendants<'a> {
|
||||||
queue: VecDeque<Ref>,
|
inner: Descendants<'a>,
|
||||||
tree: &'a RojoTree,
|
tree: &'a RojoTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,43 +182,50 @@ impl<'a> Iterator for RojoDescendants<'a> {
|
|||||||
type Item = InstanceWithMeta<'a>;
|
type Item = InstanceWithMeta<'a>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let id = self.queue.pop_front()?;
|
let instance = self.inner.next()?;
|
||||||
|
|
||||||
let instance = self
|
|
||||||
.tree
|
|
||||||
.inner
|
|
||||||
.get_by_ref(id)
|
|
||||||
.expect("Instance did not exist");
|
|
||||||
|
|
||||||
let metadata = self
|
let metadata = self
|
||||||
.tree
|
.tree
|
||||||
.get_metadata(instance.referent())
|
.get_metadata(instance.get_id())
|
||||||
.expect("Metadata did not exist for instance");
|
.expect("Metadata did not exist for instance");
|
||||||
|
|
||||||
self.queue.extend(instance.children().iter().copied());
|
|
||||||
|
|
||||||
Some(InstanceWithMeta { instance, metadata })
|
Some(InstanceWithMeta { instance, metadata })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RojoTree's equivalent of `&'a Instance`.
|
/// RojoTree's equivalent of `RbxInstanceProperties`.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct InstancePropertiesWithMeta {
|
||||||
|
pub properties: RbxInstanceProperties,
|
||||||
|
pub metadata: InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstancePropertiesWithMeta {
|
||||||
|
pub fn new(properties: RbxInstanceProperties, metadata: InstanceMetadata) -> Self {
|
||||||
|
InstancePropertiesWithMeta {
|
||||||
|
properties,
|
||||||
|
metadata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RojoTree's equivalent of `&'a RbxInstance`.
|
||||||
///
|
///
|
||||||
/// This has to be a value type for RojoTree because the instance and metadata
|
/// This has to be a value type for RojoTree because the instance and metadata
|
||||||
/// are stored in different places. The mutable equivalent is
|
/// are stored in different places. The mutable equivalent is
|
||||||
/// `InstanceWithMetaMut`.
|
/// `InstanceWithMetaMut`.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct InstanceWithMeta<'a> {
|
pub struct InstanceWithMeta<'a> {
|
||||||
instance: &'a Instance,
|
instance: &'a RbxInstance,
|
||||||
metadata: &'a InstanceMetadata,
|
metadata: &'a InstanceMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InstanceWithMeta<'a> {
|
impl<'a> InstanceWithMeta<'a> {
|
||||||
pub fn id(&self) -> Ref {
|
pub fn id(&self) -> RbxId {
|
||||||
self.instance.referent()
|
self.instance.get_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent(&self) -> Ref {
|
pub fn parent(&self) -> Option<RbxId> {
|
||||||
self.instance.parent()
|
self.instance.get_parent_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &'a str {
|
pub fn name(&self) -> &'a str {
|
||||||
@@ -232,15 +233,15 @@ impl<'a> InstanceWithMeta<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_name(&self) -> &'a str {
|
pub fn class_name(&self) -> &'a str {
|
||||||
&self.instance.class
|
&self.instance.class_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn properties(&self) -> &'a HashMap<String, Variant> {
|
pub fn properties(&self) -> &'a HashMap<String, RbxValue> {
|
||||||
&self.instance.properties
|
&self.instance.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn children(&self) -> &'a [Ref] {
|
pub fn children(&self) -> &'a [RbxId] {
|
||||||
self.instance.children()
|
self.instance.get_children_ids()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metadata(&self) -> &'a InstanceMetadata {
|
pub fn metadata(&self) -> &'a InstanceMetadata {
|
||||||
@@ -248,20 +249,20 @@ impl<'a> InstanceWithMeta<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RojoTree's equivalent of `&'a mut Instance`.
|
/// RojoTree's equivalent of `&'a mut RbxInstance`.
|
||||||
///
|
///
|
||||||
/// This has to be a value type for RojoTree because the instance and metadata
|
/// This has to be a value type for RojoTree because the instance and metadata
|
||||||
/// are stored in different places. The immutable equivalent is
|
/// are stored in different places. The immutable equivalent is
|
||||||
/// `InstanceWithMeta`.
|
/// `InstanceWithMeta`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstanceWithMetaMut<'a> {
|
pub struct InstanceWithMetaMut<'a> {
|
||||||
instance: &'a mut Instance,
|
instance: &'a mut RbxInstance,
|
||||||
metadata: &'a mut InstanceMetadata,
|
metadata: &'a mut InstanceMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceWithMetaMut<'_> {
|
impl InstanceWithMetaMut<'_> {
|
||||||
pub fn id(&self) -> Ref {
|
pub fn id(&self) -> RbxId {
|
||||||
self.instance.referent()
|
self.instance.get_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
@@ -273,23 +274,23 @@ impl InstanceWithMetaMut<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_name(&self) -> &str {
|
pub fn class_name(&self) -> &str {
|
||||||
&self.instance.class
|
&self.instance.class_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_name_mut(&mut self) -> &mut String {
|
pub fn class_name_mut(&mut self) -> &mut String {
|
||||||
&mut self.instance.class
|
&mut self.instance.class_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn properties(&self) -> &HashMap<String, Variant> {
|
pub fn properties(&self) -> &HashMap<String, RbxValue> {
|
||||||
&self.instance.properties
|
&self.instance.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn properties_mut(&mut self) -> &mut HashMap<String, Variant> {
|
pub fn properties_mut(&mut self) -> &mut HashMap<String, RbxValue> {
|
||||||
&mut self.instance.properties
|
&mut self.instance.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn children(&self) -> &[Ref] {
|
pub fn children(&self) -> &[RbxId] {
|
||||||
self.instance.children()
|
self.instance.get_children_ids()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metadata(&self) -> &InstanceMetadata {
|
pub fn metadata(&self) -> &InstanceMetadata {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::{collections::BTreeMap, path::Path};
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use memofs::{IoResultExt, Vfs};
|
use memofs::{IoResultExt, Vfs};
|
||||||
|
use rbx_dom_weak::RbxValue;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||||
@@ -29,7 +30,9 @@ pub fn snapshot_csv(
|
|||||||
.name(instance_name)
|
.name(instance_name)
|
||||||
.class_name("LocalizationTable")
|
.class_name("LocalizationTable")
|
||||||
.properties(hashmap! {
|
.properties(hashmap! {
|
||||||
"Contents".to_owned() => table_contents.into(),
|
"Contents".to_owned() => RbxValue::String {
|
||||||
|
value: table_contents,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.metadata(
|
.metadata(
|
||||||
InstanceMetadata::new()
|
InstanceMetadata::new()
|
||||||
@@ -38,8 +41,8 @@ pub fn snapshot_csv(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||||
metadata.apply_all(&mut snapshot)?;
|
metadata.apply_all(&mut snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ pub fn snapshot_dir(context: &InstanceContext, vfs: &Vfs, path: &Path) -> Snapsh
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||||
let mut metadata = DirectoryMetadata::from_slice(&meta_contents, meta_path)?;
|
let mut metadata = DirectoryMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||||
metadata.apply_all(&mut snapshot)?;
|
metadata.apply_all(&mut snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::path::Path;
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use memofs::{IoResultExt, Vfs};
|
use memofs::{IoResultExt, Vfs};
|
||||||
|
use rbx_dom_weak::RbxValue;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lua_ast::{Expression, Statement},
|
lua_ast::{Expression, Statement},
|
||||||
@@ -25,7 +26,9 @@ pub fn snapshot_json(
|
|||||||
let as_lua = json_to_lua(value).to_string();
|
let as_lua = json_to_lua(value).to_string();
|
||||||
|
|
||||||
let properties = hashmap! {
|
let properties = hashmap! {
|
||||||
"Source".to_owned() => as_lua.into(),
|
"Source".to_owned() => RbxValue::String {
|
||||||
|
value: as_lua,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let meta_path = path.with_file_name(format!("{}.meta.json", instance_name));
|
let meta_path = path.with_file_name(format!("{}.meta.json", instance_name));
|
||||||
@@ -42,8 +45,8 @@ pub fn snapshot_json(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||||
metadata.apply_all(&mut snapshot)?;
|
metadata.apply_all(&mut snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
use std::{borrow::Cow, collections::HashMap, path::Path, str};
|
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use memofs::Vfs;
|
use memofs::Vfs;
|
||||||
|
use rbx_dom_weak::UnresolvedRbxValue;
|
||||||
|
use rbx_reflection::try_resolve_value;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::snapshot::{InstanceContext, InstanceSnapshot};
|
||||||
resolution::UnresolvedValue,
|
|
||||||
snapshot::{InstanceContext, InstanceSnapshot},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::middleware::SnapshotInstanceResult;
|
use super::middleware::SnapshotInstanceResult;
|
||||||
|
|
||||||
@@ -18,20 +17,10 @@ pub fn snapshot_json_model(
|
|||||||
instance_name: &str,
|
instance_name: &str,
|
||||||
) -> SnapshotInstanceResult {
|
) -> SnapshotInstanceResult {
|
||||||
let contents = vfs.read(path)?;
|
let contents = vfs.read(path)?;
|
||||||
let contents_str = str::from_utf8(&contents)
|
let instance: JsonModel = serde_json::from_slice(&contents)
|
||||||
.with_context(|| format!("File was not valid UTF-8: {}", path.display()))?;
|
|
||||||
|
|
||||||
if contents_str.trim().is_empty() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let instance: JsonModel = serde_json::from_str(contents_str)
|
|
||||||
.with_context(|| format!("File is not a valid JSON model: {}", path.display()))?;
|
.with_context(|| format!("File is not a valid JSON model: {}", path.display()))?;
|
||||||
|
|
||||||
let mut snapshot = instance
|
let mut snapshot = instance.core.into_snapshot(instance_name.to_owned());
|
||||||
.core
|
|
||||||
.into_snapshot(instance_name.to_owned())
|
|
||||||
.with_context(|| format!("Could not load JSON model: {}", path.display()))?;
|
|
||||||
|
|
||||||
snapshot.metadata = snapshot
|
snapshot.metadata = snapshot
|
||||||
.metadata
|
.metadata
|
||||||
@@ -69,32 +58,36 @@ struct JsonModelCore {
|
|||||||
children: Vec<JsonModelInstance>,
|
children: Vec<JsonModelInstance>,
|
||||||
|
|
||||||
#[serde(default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
|
#[serde(default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
|
||||||
properties: HashMap<String, UnresolvedValue>,
|
properties: HashMap<String, UnresolvedRbxValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsonModelCore {
|
impl JsonModelCore {
|
||||||
fn into_snapshot(self, name: String) -> anyhow::Result<InstanceSnapshot> {
|
fn into_snapshot(self, name: String) -> InstanceSnapshot {
|
||||||
let class_name = self.class_name;
|
let class_name = self.class_name;
|
||||||
|
|
||||||
let mut children = Vec::with_capacity(self.children.len());
|
let children = self
|
||||||
for child in self.children {
|
.children
|
||||||
children.push(child.core.into_snapshot(child.name)?);
|
.into_iter()
|
||||||
}
|
.map(|child| child.core.into_snapshot(child.name))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut properties = HashMap::with_capacity(self.properties.len());
|
let properties = self
|
||||||
for (key, unresolved) in self.properties {
|
.properties
|
||||||
let value = unresolved.resolve(&class_name, &key)?;
|
.into_iter()
|
||||||
properties.insert(key, value);
|
.map(|(key, value)| {
|
||||||
}
|
try_resolve_value(&class_name, &key, &value).map(|resolved| (key, resolved))
|
||||||
|
})
|
||||||
|
.collect::<Result<HashMap<_, _>, _>>()
|
||||||
|
.expect("TODO: Handle rbx_reflection errors");
|
||||||
|
|
||||||
Ok(InstanceSnapshot {
|
InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
metadata: Default::default(),
|
metadata: Default::default(),
|
||||||
name: Cow::Owned(name),
|
name: Cow::Owned(name),
|
||||||
class_name: Cow::Owned(class_name),
|
class_name: Cow::Owned(class_name),
|
||||||
properties,
|
properties,
|
||||||
children,
|
children,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::{path::Path, str};
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use memofs::{IoResultExt, Vfs};
|
use memofs::{IoResultExt, Vfs};
|
||||||
|
use rbx_dom_weak::RbxValue;
|
||||||
|
|
||||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||||
|
|
||||||
@@ -37,7 +38,9 @@ pub fn snapshot_lua(context: &InstanceContext, vfs: &Vfs, path: &Path) -> Snapsh
|
|||||||
.name(instance_name)
|
.name(instance_name)
|
||||||
.class_name(class_name)
|
.class_name(class_name)
|
||||||
.properties(hashmap! {
|
.properties(hashmap! {
|
||||||
"Source".to_owned() => contents_str.into(),
|
"Source".to_owned() => RbxValue::String {
|
||||||
|
value: contents_str,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.metadata(
|
.metadata(
|
||||||
InstanceMetadata::new()
|
InstanceMetadata::new()
|
||||||
@@ -47,8 +50,8 @@ pub fn snapshot_lua(context: &InstanceContext, vfs: &Vfs, path: &Path) -> Snapsh
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||||
metadata.apply_all(&mut snapshot)?;
|
metadata.apply_all(&mut snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use std::{borrow::Cow, collections::HashMap, path::PathBuf};
|
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||||
|
|
||||||
use anyhow::{format_err, Context};
|
use anyhow::Context;
|
||||||
|
use rbx_dom_weak::UnresolvedRbxValue;
|
||||||
|
use rbx_reflection::try_resolve_value;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{resolution::UnresolvedValue, snapshot::InstanceSnapshot};
|
use crate::snapshot::InstanceSnapshot;
|
||||||
|
|
||||||
/// Represents metadata in a sibling file with the same basename.
|
/// Represents metadata in a sibling file with the same basename.
|
||||||
///
|
///
|
||||||
@@ -16,23 +18,17 @@ pub struct AdjacentMetadata {
|
|||||||
pub ignore_unknown_instances: Option<bool>,
|
pub ignore_unknown_instances: Option<bool>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||||
pub properties: HashMap<String, UnresolvedValue>,
|
pub properties: HashMap<String, UnresolvedRbxValue>,
|
||||||
|
|
||||||
#[serde(skip)]
|
|
||||||
pub path: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AdjacentMetadata {
|
impl AdjacentMetadata {
|
||||||
pub fn from_slice(slice: &[u8], path: PathBuf) -> anyhow::Result<Self> {
|
pub fn from_slice(slice: &[u8], path: &Path) -> anyhow::Result<Self> {
|
||||||
let mut meta: Self = serde_json::from_slice(slice).with_context(|| {
|
serde_json::from_slice(slice).with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"File contained malformed .meta.json data: {}",
|
"File contained malformed .meta.json data: {}",
|
||||||
path.display()
|
path.display()
|
||||||
)
|
)
|
||||||
})?;
|
})
|
||||||
|
|
||||||
meta.path = path;
|
|
||||||
Ok(meta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
|
pub fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
@@ -41,24 +37,23 @@ impl AdjacentMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
pub fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
let path = &self.path;
|
let class_name = &snapshot.class_name;
|
||||||
|
|
||||||
for (key, unresolved) in self.properties.drain() {
|
let source_properties = self.properties.drain().map(|(key, value)| {
|
||||||
let value = unresolved
|
try_resolve_value(class_name, &key, &value)
|
||||||
.resolve(&snapshot.class_name, &key)
|
.map(|resolved| (key, resolved))
|
||||||
.with_context(|| format!("error applying meta file {}", path.display()))?;
|
.expect("TODO: Handle rbx_reflection errors")
|
||||||
|
});
|
||||||
|
|
||||||
|
for (key, value) in source_properties {
|
||||||
snapshot.properties.insert(key, value);
|
snapshot.properties.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
self.apply_ignore_unknown_instances(snapshot);
|
self.apply_ignore_unknown_instances(snapshot);
|
||||||
self.apply_properties(snapshot)?;
|
self.apply_properties(snapshot);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add method to allow selectively applying parts of metadata and
|
// TODO: Add method to allow selectively applying parts of metadata and
|
||||||
@@ -76,50 +71,37 @@ pub struct DirectoryMetadata {
|
|||||||
pub ignore_unknown_instances: Option<bool>,
|
pub ignore_unknown_instances: Option<bool>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||||
pub properties: HashMap<String, UnresolvedValue>,
|
pub properties: HashMap<String, UnresolvedRbxValue>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub class_name: Option<String>,
|
pub class_name: Option<String>,
|
||||||
|
|
||||||
#[serde(skip)]
|
|
||||||
pub path: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectoryMetadata {
|
impl DirectoryMetadata {
|
||||||
pub fn from_slice(slice: &[u8], path: PathBuf) -> anyhow::Result<Self> {
|
pub fn from_slice(slice: &[u8], path: &Path) -> anyhow::Result<Self> {
|
||||||
let mut meta: Self = serde_json::from_slice(slice).with_context(|| {
|
serde_json::from_slice(slice).with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"File contained malformed init.meta.json data: {}",
|
"File contained malformed init.meta.json data: {}",
|
||||||
path.display()
|
path.display()
|
||||||
)
|
)
|
||||||
})?;
|
})
|
||||||
|
|
||||||
meta.path = path;
|
|
||||||
Ok(meta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
self.apply_ignore_unknown_instances(snapshot);
|
self.apply_ignore_unknown_instances(snapshot);
|
||||||
self.apply_class_name(snapshot)?;
|
self.apply_class_name(snapshot);
|
||||||
self.apply_properties(snapshot)?;
|
self.apply_properties(snapshot);
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_class_name(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
fn apply_class_name(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
if let Some(class_name) = self.class_name.take() {
|
if let Some(class_name) = self.class_name.take() {
|
||||||
if snapshot.class_name != "Folder" {
|
if snapshot.class_name != "Folder" {
|
||||||
// TODO: Turn into error type
|
// TODO: Turn into error type
|
||||||
return Err(format_err!(
|
panic!("className in init.meta.json can only be specified if the affected directory would turn into a Folder instance.");
|
||||||
"className in init.meta.json can only be specified if the \
|
|
||||||
affected directory would turn into a Folder instance."
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot.class_name = Cow::Owned(class_name);
|
snapshot.class_name = Cow::Owned(class_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
|
fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
@@ -128,17 +110,17 @@ impl DirectoryMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||||
let path = &self.path;
|
let class_name = &snapshot.class_name;
|
||||||
|
|
||||||
for (key, unresolved) in self.properties.drain() {
|
let source_properties = self.properties.drain().map(|(key, value)| {
|
||||||
let value = unresolved
|
try_resolve_value(class_name, &key, &value)
|
||||||
.resolve(&snapshot.class_name, &key)
|
.map(|resolved| (key, resolved))
|
||||||
.with_context(|| format!("error applying meta file {}", path.display()))?;
|
.expect("TODO: Handle rbx_reflection errors")
|
||||||
|
});
|
||||||
|
|
||||||
|
for (key, value) in source_properties {
|
||||||
snapshot.properties.insert(key, value);
|
snapshot.properties.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::{borrow::Cow, collections::HashMap, path::Path};
|
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||||
|
|
||||||
use anyhow::{bail, Context};
|
use anyhow::Context;
|
||||||
use memofs::Vfs;
|
use memofs::Vfs;
|
||||||
use rbx_reflection::ClassTag;
|
use rbx_reflection::{get_class_descriptor, try_resolve_value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
project::{Project, ProjectNode},
|
project::{Project, ProjectNode},
|
||||||
@@ -66,13 +66,11 @@ pub fn snapshot_project_node(
|
|||||||
) -> SnapshotInstanceResult {
|
) -> SnapshotInstanceResult {
|
||||||
let project_folder = project_path.parent().unwrap();
|
let project_folder = project_path.parent().unwrap();
|
||||||
|
|
||||||
let class_name_from_project = node
|
let name = Cow::Owned(instance_name.to_owned());
|
||||||
|
let mut class_name = node
|
||||||
.class_name
|
.class_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|name| Cow::Owned(name.clone()));
|
.map(|name| Cow::Owned(name.clone()));
|
||||||
let mut class_name_from_path = None;
|
|
||||||
|
|
||||||
let name = Cow::Owned(instance_name.to_owned());
|
|
||||||
let mut properties = HashMap::new();
|
let mut properties = HashMap::new();
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
let mut metadata = InstanceMetadata::default();
|
let mut metadata = InstanceMetadata::default();
|
||||||
@@ -87,7 +85,24 @@ pub fn snapshot_project_node(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(snapshot) = snapshot_from_vfs(context, vfs, &path)? {
|
if let Some(snapshot) = snapshot_from_vfs(context, vfs, &path)? {
|
||||||
class_name_from_path = Some(snapshot.class_name);
|
// If a class name was already specified, then it'll override the
|
||||||
|
// class name of this snapshot ONLY if it's a Folder.
|
||||||
|
//
|
||||||
|
// This restriction is in place to prevent applying properties to
|
||||||
|
// instances that don't make sense. The primary use-case for using
|
||||||
|
// $className and $path at the same time is to use a directory as a
|
||||||
|
// service in a place file.
|
||||||
|
class_name = match class_name {
|
||||||
|
Some(class_name) => {
|
||||||
|
if snapshot.class_name == "Folder" {
|
||||||
|
Some(class_name)
|
||||||
|
} else {
|
||||||
|
// TODO: Turn this into an error object.
|
||||||
|
panic!("If $className and $path are specified, $path must yield an instance of class Folder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Some(snapshot.class_name),
|
||||||
|
};
|
||||||
|
|
||||||
// Properties from the snapshot are pulled in unchanged, and
|
// Properties from the snapshot are pulled in unchanged, and
|
||||||
// overridden by properties set on the project node.
|
// overridden by properties set on the project node.
|
||||||
@@ -114,66 +129,34 @@ pub fn snapshot_project_node(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_name_from_inference = infer_class_name(&name, parent_class);
|
let class_name = class_name
|
||||||
|
.or_else(|| {
|
||||||
|
// If className wasn't defined from another source, we may be able
|
||||||
|
// to infer one.
|
||||||
|
|
||||||
let class_name = match (
|
let parent_class = parent_class?;
|
||||||
class_name_from_project,
|
|
||||||
class_name_from_path,
|
|
||||||
class_name_from_inference,
|
|
||||||
) {
|
|
||||||
// These are the easy, happy paths!
|
|
||||||
(Some(project), None, None) => project,
|
|
||||||
(None, Some(path), None) => path,
|
|
||||||
(None, None, Some(inference)) => inference,
|
|
||||||
|
|
||||||
// If the user specifies a class name, but there's an inferred class
|
if parent_class == "DataModel" {
|
||||||
// name, we prefer the name listed explicitly by the user.
|
// Members of DataModel with names that match known services are
|
||||||
(Some(project), None, Some(_)) => project,
|
// probably supposed to be those services.
|
||||||
|
|
||||||
// If the user has a $path pointing to a folder and we're able to infer
|
let descriptor = get_class_descriptor(&name)?;
|
||||||
// a class name, let's use the inferred name. If the path we're pointing
|
|
||||||
// to isn't a folder, though, that's a user error.
|
if descriptor.is_service() {
|
||||||
(None, Some(path), Some(inference)) => {
|
return Some(name.clone());
|
||||||
if path == "Folder" {
|
}
|
||||||
inference
|
} else if parent_class == "StarterPlayer" {
|
||||||
} else {
|
// StarterPlayer has two special members with their own classes.
|
||||||
path
|
|
||||||
|
if name == "StarterPlayerScripts" || name == "StarterCharacterScripts" {
|
||||||
|
return Some(name.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
(Some(project), Some(path), _) => {
|
None
|
||||||
if path == "Folder" {
|
})
|
||||||
project
|
// TODO: Turn this into an error object.
|
||||||
} else {
|
.expect("$className or $path must be specified");
|
||||||
bail!(
|
|
||||||
"ClassName for Instance \"{}\" was specified in both the project file (as \"{}\") and from the filesystem (as \"{}\").\n\
|
|
||||||
If $className and $path are both set, $path must refer to a Folder.
|
|
||||||
\n\
|
|
||||||
Project path: {}\n\
|
|
||||||
Filesystem path: {}\n",
|
|
||||||
instance_name,
|
|
||||||
project,
|
|
||||||
path,
|
|
||||||
project_path.display(),
|
|
||||||
node.path.as_ref().unwrap().display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(None, None, None) => {
|
|
||||||
bail!(
|
|
||||||
"Instance \"{}\" is missing some required information.\n\
|
|
||||||
One of the following must be true:\n\
|
|
||||||
- $className must be set to the name of a Roblox class\n\
|
|
||||||
- $path must be set to a path of an instance\n\
|
|
||||||
- The instance must be a known service, like ReplicatedStorage\n\
|
|
||||||
\n\
|
|
||||||
Project path: {}",
|
|
||||||
instance_name,
|
|
||||||
project_path.display(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (child_name, child_project_node) in &node.children {
|
for (child_name, child_project_node) in &node.children {
|
||||||
if let Some(child) = snapshot_project_node(
|
if let Some(child) = snapshot_project_node(
|
||||||
@@ -188,32 +171,11 @@ pub fn snapshot_project_node(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, unresolved) in &node.properties {
|
for (key, value) in &node.properties {
|
||||||
let value = unresolved
|
let resolved_value = try_resolve_value(&class_name, key, value)
|
||||||
.clone()
|
.expect("TODO: Properly handle value resolution errors");
|
||||||
.resolve(&class_name, key)
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Unresolvable property in project at path {}",
|
|
||||||
project_path.display()
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
match key.as_str() {
|
properties.insert(key.clone(), resolved_value);
|
||||||
"Name" | "Parent" => {
|
|
||||||
log::warn!(
|
|
||||||
"Property '{}' cannot be set manually, ignoring. Attempted to set in '{}' at {}",
|
|
||||||
key,
|
|
||||||
instance_name,
|
|
||||||
project_path.display()
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
properties.insert(key.clone(), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user specified $ignoreUnknownInstances, overwrite the existing
|
// If the user specified $ignoreUnknownInstances, overwrite the existing
|
||||||
@@ -247,32 +209,6 @@ pub fn snapshot_project_node(
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Cow<'static, str>> {
|
|
||||||
// If className wasn't defined from another source, we may be able
|
|
||||||
// to infer one.
|
|
||||||
|
|
||||||
let parent_class = parent_class?;
|
|
||||||
|
|
||||||
if parent_class == "DataModel" {
|
|
||||||
// Members of DataModel with names that match known services are
|
|
||||||
// probably supposed to be those services.
|
|
||||||
|
|
||||||
let descriptor = rbx_reflection_database::get().classes.get(name)?;
|
|
||||||
|
|
||||||
if descriptor.tags.contains(&ClassTag::Service) {
|
|
||||||
return Some(Cow::Owned(name.to_owned()));
|
|
||||||
}
|
|
||||||
} else if parent_class == "StarterPlayer" {
|
|
||||||
// StarterPlayer has two special members with their own classes.
|
|
||||||
|
|
||||||
if name == "StarterPlayerScripts" || name == "StarterCharacterScripts" {
|
|
||||||
return Some(Cow::Owned(name.to_owned()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[cfg(feature = "broken-tests")]
|
// #[cfg(feature = "broken-tests")]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use std::path::Path;
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use memofs::Vfs;
|
use memofs::Vfs;
|
||||||
|
use rbx_dom_weak::{RbxInstanceProperties, RbxTree};
|
||||||
|
|
||||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||||
|
|
||||||
@@ -13,11 +14,18 @@ pub fn snapshot_rbxm(
|
|||||||
path: &Path,
|
path: &Path,
|
||||||
instance_name: &str,
|
instance_name: &str,
|
||||||
) -> SnapshotInstanceResult {
|
) -> SnapshotInstanceResult {
|
||||||
let temp_tree = rbx_binary::from_reader_default(vfs.read(path)?.as_slice())
|
let mut temp_tree = RbxTree::new(RbxInstanceProperties {
|
||||||
|
name: "DataModel".to_owned(),
|
||||||
|
class_name: "DataModel".to_owned(),
|
||||||
|
properties: HashMap::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let root_id = temp_tree.get_root_id();
|
||||||
|
rbx_binary::decode(&mut temp_tree, root_id, vfs.read(path)?.as_slice())
|
||||||
.with_context(|| format!("Malformed rbxm file: {}", path.display()))?;
|
.with_context(|| format!("Malformed rbxm file: {}", path.display()))?;
|
||||||
|
|
||||||
let root_instance = temp_tree.root();
|
let root_instance = temp_tree.get_instance(root_id).unwrap();
|
||||||
let children = root_instance.children();
|
let children = root_instance.get_children_ids();
|
||||||
|
|
||||||
if children.len() == 1 {
|
if children.len() == 1 {
|
||||||
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0])
|
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0])
|
||||||
@@ -32,7 +40,7 @@ pub fn snapshot_rbxm(
|
|||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
} else {
|
} else {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Rojo currently only supports model files with one top-level instance.\n\n \
|
"Rojo doesn't have support for model files with zero or more than one top-level instances yet.\n\n \
|
||||||
Check the model file at path {}",
|
Check the model file at path {}",
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ pub fn snapshot_rbxmx(
|
|||||||
let temp_tree = rbx_xml::from_reader(vfs.read(path)?.as_slice(), options)
|
let temp_tree = rbx_xml::from_reader(vfs.read(path)?.as_slice(), options)
|
||||||
.with_context(|| format!("Malformed rbxm file: {}", path.display()))?;
|
.with_context(|| format!("Malformed rbxm file: {}", path.display()))?;
|
||||||
|
|
||||||
let root_instance = temp_tree.root();
|
let root_instance = temp_tree.get_instance(temp_tree.get_root_id()).unwrap();
|
||||||
let children = root_instance.children();
|
let children = root_instance.get_children_ids();
|
||||||
|
|
||||||
if children.len() == 1 {
|
if children.len() == 1 {
|
||||||
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0])
|
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0])
|
||||||
@@ -35,7 +35,7 @@ pub fn snapshot_rbxmx(
|
|||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
} else {
|
} else {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Rojo currently only supports model files with one top-level instance.\n\n \
|
"Rojo doesn't have support for model files with zero or more than one top-level instances yet.\n\n \
|
||||||
Check the model file at path {}",
|
Check the model file at path {}",
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ name: foo
|
|||||||
class_name: IntValue
|
class_name: IntValue
|
||||||
properties:
|
properties:
|
||||||
Value:
|
Value:
|
||||||
Type: Int64
|
Type: Int32
|
||||||
Value: 5
|
Value: 5
|
||||||
children:
|
children:
|
||||||
- snapshot_id: ~
|
- snapshot_id: ~
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::{path::Path, str};
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use memofs::{IoResultExt, Vfs};
|
use memofs::{IoResultExt, Vfs};
|
||||||
|
use rbx_dom_weak::RbxValue;
|
||||||
|
|
||||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||||
|
|
||||||
@@ -20,7 +21,9 @@ pub fn snapshot_txt(
|
|||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let properties = hashmap! {
|
let properties = hashmap! {
|
||||||
"Value".to_owned() => contents_str.into(),
|
"Value".to_owned() => RbxValue::String {
|
||||||
|
value: contents_str,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let meta_path = path.with_file_name(format!("{}.meta.json", instance_name));
|
let meta_path = path.with_file_name(format!("{}.meta.json", instance_name));
|
||||||
@@ -37,8 +40,8 @@ pub fn snapshot_txt(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||||
metadata.apply_all(&mut snapshot)?;
|
metadata.apply_all(&mut snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
use rojo_insta_ext::RedactionMap;
|
use rojo_insta_ext::RedactionMap;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
@@ -29,15 +29,15 @@ pub fn intern_tree(tree: &RojoTree, redactions: &mut RedactionMap) {
|
|||||||
/// Copy of data from RojoTree in the right shape to have useful snapshots.
|
/// Copy of data from RojoTree in the right shape to have useful snapshots.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct InstanceView {
|
struct InstanceView {
|
||||||
id: Ref,
|
id: RbxId,
|
||||||
name: String,
|
name: String,
|
||||||
class_name: String,
|
class_name: String,
|
||||||
properties: HashMap<String, Variant>,
|
properties: HashMap<String, RbxValue>,
|
||||||
metadata: InstanceMetadata,
|
metadata: InstanceMetadata,
|
||||||
children: Vec<InstanceView>,
|
children: Vec<InstanceView>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_instance_view(tree: &RojoTree, id: Ref) -> InstanceView {
|
fn extract_instance_view(tree: &RojoTree, id: RbxId) -> InstanceView {
|
||||||
let instance = tree.get_instance(id).unwrap();
|
let instance = tree.get_instance(id).unwrap();
|
||||||
|
|
||||||
InstanceView {
|
InstanceView {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
//! Defines Rojo's HTTP API, all under /api. These endpoints generally return
|
//! Defines Rojo's HTTP API, all under /api. These endpoints generally return
|
||||||
//! JSON.
|
//! JSON.
|
||||||
|
|
||||||
use std::{collections::HashMap, fs, path::PathBuf, str::FromStr, sync::Arc};
|
use std::{collections::HashMap, fs, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use futures::{Future, Stream};
|
use futures::{Future, Stream};
|
||||||
|
|
||||||
use hyper::{service::Service, Body, Method, Request, StatusCode};
|
use hyper::{service::Service, Body, Method, Request, StatusCode};
|
||||||
use rbx_dom_weak::types::Ref;
|
use rbx_dom_weak::RbxId;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
serve_session::ServeSession,
|
serve_session::ServeSession,
|
||||||
@@ -69,8 +69,6 @@ impl ApiService {
|
|||||||
session_id: self.serve_session.session_id(),
|
session_id: self.serve_session.session_id(),
|
||||||
project_name: self.serve_session.project_name().to_owned(),
|
project_name: self.serve_session.project_name().to_owned(),
|
||||||
expected_place_ids: self.serve_session.serve_place_ids().cloned(),
|
expected_place_ids: self.serve_session.serve_place_ids().cloned(),
|
||||||
place_id: self.serve_session.place_id(),
|
|
||||||
game_id: self.serve_session.game_id(),
|
|
||||||
root_instance_id,
|
root_instance_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -202,11 +200,11 @@ impl ApiService {
|
|||||||
|
|
||||||
fn handle_api_read(&self, request: Request<Body>) -> <Self as Service>::Future {
|
fn handle_api_read(&self, request: Request<Body>) -> <Self as Service>::Future {
|
||||||
let argument = &request.uri().path()["/api/read/".len()..];
|
let argument = &request.uri().path()["/api/read/".len()..];
|
||||||
let requested_ids: Result<Vec<Ref>, _> = argument.split(',').map(Ref::from_str).collect();
|
let requested_ids: Option<Vec<RbxId>> = argument.split(',').map(RbxId::parse_str).collect();
|
||||||
|
|
||||||
let requested_ids = match requested_ids {
|
let requested_ids = match requested_ids {
|
||||||
Ok(ids) => ids,
|
Some(ids) => ids,
|
||||||
Err(_) => {
|
None => {
|
||||||
return json(
|
return json(
|
||||||
ErrorResponse::bad_request("Malformed ID list"),
|
ErrorResponse::bad_request("Malformed ID list"),
|
||||||
StatusCode::BAD_REQUEST,
|
StatusCode::BAD_REQUEST,
|
||||||
@@ -241,9 +239,9 @@ impl ApiService {
|
|||||||
/// Open a script with the given ID in the user's default text editor.
|
/// Open a script with the given ID in the user's default text editor.
|
||||||
fn handle_api_open(&self, request: Request<Body>) -> <Self as Service>::Future {
|
fn handle_api_open(&self, request: Request<Body>) -> <Self as Service>::Future {
|
||||||
let argument = &request.uri().path()["/api/open/".len()..];
|
let argument = &request.uri().path()["/api/open/".len()..];
|
||||||
let requested_id = match Ref::from_str(argument) {
|
let requested_id = match RbxId::parse_str(argument) {
|
||||||
Ok(id) => id,
|
Some(id) => id,
|
||||||
Err(_) => {
|
None => {
|
||||||
return json(
|
return json(
|
||||||
ErrorResponse::bad_request("Invalid instance ID"),
|
ErrorResponse::bad_request("Invalid instance ID"),
|
||||||
StatusCode::BAD_REQUEST,
|
StatusCode::BAD_REQUEST,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
};
|
};
|
||||||
|
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -17,28 +17,28 @@ use crate::{
|
|||||||
pub(crate) const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub(crate) const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
/// Current protocol version, which is required to match.
|
/// Current protocol version, which is required to match.
|
||||||
pub const PROTOCOL_VERSION: u64 = 4;
|
pub const PROTOCOL_VERSION: u64 = 3;
|
||||||
|
|
||||||
/// Message returned by Rojo API when a change has occurred.
|
/// Message returned by Rojo API when a change has occurred.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SubscribeMessage<'a> {
|
pub struct SubscribeMessage<'a> {
|
||||||
pub removed: Vec<Ref>,
|
pub removed: Vec<RbxId>,
|
||||||
pub added: HashMap<Ref, Instance<'a>>,
|
pub added: HashMap<RbxId, Instance<'a>>,
|
||||||
pub updated: Vec<InstanceUpdate>,
|
pub updated: Vec<InstanceUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct InstanceUpdate {
|
pub struct InstanceUpdate {
|
||||||
pub id: Ref,
|
pub id: RbxId,
|
||||||
pub changed_name: Option<String>,
|
pub changed_name: Option<String>,
|
||||||
pub changed_class_name: Option<String>,
|
pub changed_class_name: Option<String>,
|
||||||
|
|
||||||
// TODO: Transform from HashMap<String, Option<_>> to something else, since
|
// TODO: Transform from HashMap<String, Option<_>> to something else, since
|
||||||
// null will get lost when decoding from JSON in some languages.
|
// null will get lost when decoding from JSON in some languages.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub changed_properties: HashMap<String, Option<Variant>>,
|
pub changed_properties: HashMap<String, Option<RbxValue>>,
|
||||||
pub changed_metadata: Option<InstanceMetadata>,
|
pub changed_metadata: Option<InstanceMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,36 +59,23 @@ impl InstanceMetadata {
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub struct Instance<'a> {
|
pub struct Instance<'a> {
|
||||||
pub id: Ref,
|
pub id: RbxId,
|
||||||
pub parent: Ref,
|
pub parent: Option<RbxId>,
|
||||||
pub name: Cow<'a, str>,
|
pub name: Cow<'a, str>,
|
||||||
pub class_name: Cow<'a, str>,
|
pub class_name: Cow<'a, str>,
|
||||||
pub properties: HashMap<String, Cow<'a, Variant>>,
|
pub properties: Cow<'a, HashMap<String, RbxValue>>,
|
||||||
pub children: Cow<'a, [Ref]>,
|
pub children: Cow<'a, [RbxId]>,
|
||||||
pub metadata: Option<InstanceMetadata>,
|
pub metadata: Option<InstanceMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Instance<'a> {
|
impl<'a> Instance<'a> {
|
||||||
pub(crate) fn from_rojo_instance(source: InstanceWithMeta<'_>) -> Instance<'_> {
|
pub(crate) fn from_rojo_instance(source: InstanceWithMeta<'_>) -> Instance<'_> {
|
||||||
let properties = source
|
|
||||||
.properties()
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(key, value)| {
|
|
||||||
// SharedString values can't be serialized via Serde
|
|
||||||
if matches!(value, Variant::SharedString(_)) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some((key.clone(), Cow::Borrowed(value)))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Instance {
|
Instance {
|
||||||
id: source.id(),
|
id: source.id(),
|
||||||
parent: source.parent(),
|
parent: source.parent(),
|
||||||
name: Cow::Borrowed(source.name()),
|
name: Cow::Borrowed(source.name()),
|
||||||
class_name: Cow::Borrowed(source.class_name()),
|
class_name: Cow::Borrowed(source.class_name()),
|
||||||
properties,
|
properties: Cow::Borrowed(source.properties()),
|
||||||
children: Cow::Borrowed(source.children()),
|
children: Cow::Borrowed(source.children()),
|
||||||
metadata: Some(InstanceMetadata::from_rojo_metadata(source.metadata())),
|
metadata: Some(InstanceMetadata::from_rojo_metadata(source.metadata())),
|
||||||
}
|
}
|
||||||
@@ -104,9 +91,7 @@ pub struct ServerInfoResponse {
|
|||||||
pub protocol_version: u64,
|
pub protocol_version: u64,
|
||||||
pub project_name: String,
|
pub project_name: String,
|
||||||
pub expected_place_ids: Option<HashSet<u64>>,
|
pub expected_place_ids: Option<HashSet<u64>>,
|
||||||
pub game_id: Option<u64>,
|
pub root_instance_id: RbxId,
|
||||||
pub place_id: Option<u64>,
|
|
||||||
pub root_instance_id: Ref,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response body from /api/read/{id}
|
/// Response body from /api/read/{id}
|
||||||
@@ -115,17 +100,17 @@ pub struct ServerInfoResponse {
|
|||||||
pub struct ReadResponse<'a> {
|
pub struct ReadResponse<'a> {
|
||||||
pub session_id: SessionId,
|
pub session_id: SessionId,
|
||||||
pub message_cursor: u32,
|
pub message_cursor: u32,
|
||||||
pub instances: HashMap<Ref, Instance<'a>>,
|
pub instances: HashMap<RbxId, Instance<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct WriteRequest {
|
pub struct WriteRequest {
|
||||||
pub session_id: SessionId,
|
pub session_id: SessionId,
|
||||||
pub removed: Vec<Ref>,
|
pub removed: Vec<RbxId>,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub added: HashMap<Ref, ()>,
|
pub added: HashMap<RbxId, ()>,
|
||||||
pub updated: Vec<InstanceUpdate>,
|
pub updated: Vec<InstanceUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{borrow::Cow, sync::Arc, time::Duration};
|
|||||||
use futures::{future, Future};
|
use futures::{future, Future};
|
||||||
use hyper::{header, service::Service, Body, Method, Request, Response, StatusCode};
|
use hyper::{header, service::Service, Body, Method, Request, Response, StatusCode};
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use rbx_dom_weak::types::{Ref, Variant};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
use ritz::{html, Fragment, HtmlContent, HtmlSelfClosingTag};
|
use ritz::{html, Fragment, HtmlContent, HtmlSelfClosingTag};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -93,7 +93,7 @@ impl UiService {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instance(tree: &RojoTree, id: Ref) -> HtmlContent<'_> {
|
fn instance(tree: &RojoTree, id: RbxId) -> HtmlContent<'_> {
|
||||||
let instance = tree.get_instance(id).unwrap();
|
let instance = tree.get_instance(id).unwrap();
|
||||||
let children_list: Vec<_> = instance
|
let children_list: Vec<_> = instance
|
||||||
.children()
|
.children()
|
||||||
@@ -126,7 +126,7 @@ impl UiService {
|
|||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
html! {
|
html! {
|
||||||
<div class="instance-property" title={ Self::display_value(value) }>
|
<div class="instance-property" title={ Self::display_value(value) }>
|
||||||
{ key.clone() } ": " { format!("{:?}", value.ty()) }
|
{ key.clone() } ": " { format!("{:?}", value.get_type()) }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -198,7 +198,7 @@ impl UiService {
|
|||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="instance">
|
<div class="instance">
|
||||||
<label class="instance-title" for={ format!("instance-{:?}", id) }>
|
<label class="instance-title" for={ format!("instance-{}", id) }>
|
||||||
{ instance.name().to_owned() }
|
{ instance.name().to_owned() }
|
||||||
{ class_name_specifier }
|
{ class_name_specifier }
|
||||||
</label>
|
</label>
|
||||||
@@ -209,10 +209,10 @@ impl UiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_value(value: &Variant) -> String {
|
fn display_value(value: &RbxValue) -> String {
|
||||||
match value {
|
match value {
|
||||||
Variant::String(value) => value.clone(),
|
RbxValue::String { value } => value.clone(),
|
||||||
Variant::Bool(value) => value.to_string(),
|
RbxValue::Bool { value } => value.to_string(),
|
||||||
_ => format!("{:?}", value),
|
_ => format!("{:?}", value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,14 +288,14 @@ impl UiService {
|
|||||||
struct ExpandableSection<'a> {
|
struct ExpandableSection<'a> {
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
class_name: &'a str,
|
class_name: &'a str,
|
||||||
id: Ref,
|
id: RbxId,
|
||||||
expanded: bool,
|
expanded: bool,
|
||||||
content: HtmlContent<'a>,
|
content: HtmlContent<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExpandableSection<'a> {
|
impl<'a> ExpandableSection<'a> {
|
||||||
fn render(self) -> HtmlContent<'a> {
|
fn render(self) -> HtmlContent<'a> {
|
||||||
let input_id = format!("{}-{:?}", self.class_name, self.id);
|
let input_id = format!("{}-{}", self.class_name, self.id);
|
||||||
|
|
||||||
// We need to specify this input manually because Ritz doesn't have
|
// We need to specify this input manually because Ritz doesn't have
|
||||||
// support for conditional attributes like `checked`.
|
// support for conditional attributes like `checked`.
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "bad_classname_path_conflict",
|
|
||||||
"tree": {
|
|
||||||
"$className": "DataModel",
|
|
||||||
"$path": "foo.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "bad_no_classname",
|
|
||||||
"tree": {}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "enums",
|
|
||||||
"tree": {
|
|
||||||
"$className": "DataModel",
|
|
||||||
|
|
||||||
"Lighting": {
|
|
||||||
"$properties": {
|
|
||||||
"Technology": "Voxel"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "unions",
|
"name": "unions",
|
||||||
"tree": {
|
"tree": {
|
||||||
"$className": "DataModel",
|
"$path": "src"
|
||||||
|
|
||||||
"Workspace": {
|
|
||||||
"TwoParts": {
|
|
||||||
"$path": "src"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rbx_dom_weak::types::Ref;
|
use rbx_dom_weak::RbxId;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use librojo::web_api::{Instance, InstanceUpdate, ReadResponse, SubscribeResponse};
|
use librojo::web_api::{Instance, InstanceUpdate, ReadResponse, SubscribeResponse};
|
||||||
@@ -31,8 +31,8 @@ pub trait Internable<T> {
|
|||||||
fn intern(&self, redactions: &mut RedactionMap, extra: T);
|
fn intern(&self, redactions: &mut RedactionMap, extra: T);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Internable<Ref> for ReadResponse<'_> {
|
impl Internable<RbxId> for ReadResponse<'_> {
|
||||||
fn intern(&self, redactions: &mut RedactionMap, root_id: Ref) {
|
fn intern(&self, redactions: &mut RedactionMap, root_id: RbxId) {
|
||||||
redactions.intern(root_id);
|
redactions.intern(root_id);
|
||||||
|
|
||||||
let root_instance = self.instances.get(&root_id).unwrap();
|
let root_instance = self.instances.get(&root_id).unwrap();
|
||||||
@@ -43,8 +43,12 @@ impl Internable<Ref> for ReadResponse<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Internable<&'a HashMap<Ref, Instance<'_>>> for Instance<'a> {
|
impl<'a> Internable<&'a HashMap<RbxId, Instance<'_>>> for Instance<'a> {
|
||||||
fn intern(&self, redactions: &mut RedactionMap, other_instances: &HashMap<Ref, Instance<'_>>) {
|
fn intern(
|
||||||
|
&self,
|
||||||
|
redactions: &mut RedactionMap,
|
||||||
|
other_instances: &HashMap<RbxId, Instance<'_>>,
|
||||||
|
) {
|
||||||
redactions.intern(self.id);
|
redactions.intern(self.id);
|
||||||
|
|
||||||
for child_id in self.children.iter() {
|
for child_id in self.children.iter() {
|
||||||
@@ -71,7 +75,7 @@ fn intern_instance_updates(redactions: &mut RedactionMap, updates: &[InstanceUpd
|
|||||||
|
|
||||||
fn intern_instance_additions(
|
fn intern_instance_additions(
|
||||||
redactions: &mut RedactionMap,
|
redactions: &mut RedactionMap,
|
||||||
additions: &HashMap<Ref, Instance<'_>>,
|
additions: &HashMap<RbxId, Instance<'_>>,
|
||||||
) {
|
) {
|
||||||
// This method redacts in a deterministic order from a HashMap by collecting
|
// This method redacts in a deterministic order from a HashMap by collecting
|
||||||
// all of the instances that are direct children of instances we've already
|
// all of the instances that are direct children of instances we've already
|
||||||
@@ -79,7 +83,7 @@ fn intern_instance_additions(
|
|||||||
let mut added_roots = Vec::new();
|
let mut added_roots = Vec::new();
|
||||||
|
|
||||||
for (id, added) in additions {
|
for (id, added) in additions {
|
||||||
let parent_id = added.parent;
|
let parent_id = added.parent.unwrap();
|
||||||
let parent_redacted = redactions.get_redacted_value(parent_id);
|
let parent_redacted = redactions.get_redacted_value(parent_id);
|
||||||
|
|
||||||
// Here, we assume that instances are only added to other instances that
|
// Here, we assume that instances are only added to other instances that
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rbx_dom_weak::types::Ref;
|
use rbx_dom_weak::RbxId;
|
||||||
|
|
||||||
use tempfile::{tempdir, TempDir};
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ impl TestServeSession {
|
|||||||
Ok(serde_json::from_str(&body).expect("Server returned malformed response"))
|
Ok(serde_json::from_str(&body).expect("Server returned malformed response"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_api_read(&self, id: Ref) -> Result<ReadResponse, reqwest::Error> {
|
pub fn get_api_read(&self, id: RbxId) -> Result<ReadResponse, reqwest::Error> {
|
||||||
let url = format!("http://localhost:{}/api/read/{}", self.port, id);
|
let url = format!("http://localhost:{}/api/read/{}", self.port, id);
|
||||||
let body = reqwest::get(&url)?.text()?;
|
let body = reqwest::get(&url)?.text()?;
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ gen_build_tests! {
|
|||||||
server_init,
|
server_init,
|
||||||
txt,
|
txt,
|
||||||
txt_in_folder,
|
txt_in_folder,
|
||||||
unresolved_values,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_build_test(test_name: &str) {
|
fn run_build_test(test_name: &str) {
|
||||||
|
|||||||
@@ -186,37 +186,3 @@ fn move_folder_of_stuff() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_json_model() {
|
|
||||||
run_serve_test("empty_json_model", |session, mut redactions| {
|
|
||||||
let info = session.get_api_rojo().unwrap();
|
|
||||||
let root_id = info.root_instance_id;
|
|
||||||
|
|
||||||
assert_yaml_snapshot!("empty_json_model_info", redactions.redacted_yaml(info));
|
|
||||||
|
|
||||||
let read_response = session.get_api_read(root_id).unwrap();
|
|
||||||
assert_yaml_snapshot!(
|
|
||||||
"empty_json_model_all",
|
|
||||||
read_response.intern_and_redact(&mut redactions, root_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
fs::write(
|
|
||||||
session.path().join("src/test.model.json"),
|
|
||||||
r#"{"ClassName": "Model"}"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let subscribe_response = session.get_api_subscribe(0).unwrap();
|
|
||||||
assert_yaml_snapshot!(
|
|
||||||
"empty_json_model_subscribe",
|
|
||||||
subscribe_response.intern_and_redact(&mut redactions, ())
|
|
||||||
);
|
|
||||||
|
|
||||||
let read_response = session.get_api_read(root_id).unwrap();
|
|
||||||
assert_yaml_snapshot!(
|
|
||||||
"empty_json_model_all-2",
|
|
||||||
read_response.intern_and_redact(&mut redactions, root_id)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user