mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-22 21:41:37 +00:00
Merge branch 'master' of https://github.com/boatbomber/rojo into headless-api
This commit is contained in:
commit
5f4c2a7a3f
82 changed files with 10139 additions and 2429 deletions
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -53,7 +53,7 @@ jobs:
|
|||
# https://doc.rust-lang.org/rustc/platform-support.html
|
||||
include:
|
||||
- host: linux
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
label: linux-x86_64
|
||||
|
||||
|
|
|
|||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -19,3 +19,7 @@
|
|||
|
||||
# Snapshot files from the 'insta' Rust crate
|
||||
**/*.snap.new
|
||||
|
||||
# Macos file system junk
|
||||
._*
|
||||
.DS_STORE
|
||||
|
|
|
|||
35
CHANGELOG.md
35
CHANGELOG.md
|
|
@ -3,6 +3,20 @@
|
|||
## Unreleased Changes
|
||||
|
||||
* Added headless API for Studio companion plugins. ([#639])
|
||||
|
||||
[#639]: https://github.com/rojo-rbx/rojo/pull/639
|
||||
|
||||
## 7.5.1 - April 25th, 2025
|
||||
* Fixed output spam related to `Instance.Capabilities` in the plugin
|
||||
|
||||
## 7.5.0 - April 25th, 2025
|
||||
* Fixed an edge case that caused model pivots to not be built correctly in some cases ([#1027])
|
||||
* Add `blockedPlaceIds` project config field to allow blocking place ids from being live synced ([#1021])
|
||||
* Adds support for `.plugin.lua(u)` files - this applies the `Plugin` RunContext. ([#1008])
|
||||
* Added support for Roblox's `Content` type. This replaces the old `Content` type with `ContentId` to reflect Roblox's change.
|
||||
If you were previously using the fully-qualified syntax for `Content` you will need to switch it to `ContentId`.
|
||||
* Added support for `Enum` attributes
|
||||
* Significantly improved performance of `.rbxm` parsing
|
||||
* Support for a `$schema` field in all special JSON files (`.project.json`, `.model.json`, and `.meta.json`) ([#974])
|
||||
* Projects may now manually link `Ref` properties together using `Attributes`. ([#843])
|
||||
This has two parts: using `id` or `$id` in JSON files or a `Rojo_Target` attribute, an Instance
|
||||
|
|
@ -61,7 +75,7 @@
|
|||
|
||||
Additionally, the `exclude` field allows files to be excluded from the sync rule if they match a pattern specified by it. If it's not present, all files that match `pattern` will be modified using the sync rule.
|
||||
|
||||
The `use` field corresponds to one of the potential file type that Rojo will currently include in a project. Files that match the provided pattern will be treated as if they had the file extension for that file type. A full list is below:
|
||||
The `use` field corresponds to one of the potential file type that Rojo will currently include in a project. Files that match the provided pattern will be treated as if they had the file extension for that file type.
|
||||
|
||||
| `use` value | file extension |
|
||||
|:---------------|:----------------|
|
||||
|
|
@ -78,9 +92,18 @@
|
|||
| `project` | `.project.json` |
|
||||
| `ignore` | None! |
|
||||
|
||||
Additionally, there are `use` values for specific script types ([#909]):
|
||||
|
||||
| `use` value | script type |
|
||||
|:-------------------------|:---------------------------------------|
|
||||
| `legacyServerScript` | `Script` with `Enum.RunContext.Legacy` |
|
||||
| `legacyClientScript` | `LocalScript` |
|
||||
| `runContextServerScript` | `Script` with `Enum.RunContext.Server` |
|
||||
| `runContextClientScript` | `Script` with `Enum.RunContext.Client` |
|
||||
| `pluginScript` | `Script` with `Enum.RunContext.Plugin` |
|
||||
|
||||
**All** sync rules are reset between project files, so they must be specified in each one when nesting them. This is to ensure that nothing can break other projects by changing how files are synced!
|
||||
|
||||
[#639]: https://github.com/rojo-rbx/rojo/pull/639
|
||||
[#813]: https://github.com/rojo-rbx/rojo/pull/813
|
||||
[#832]: https://github.com/rojo-rbx/rojo/pull/832
|
||||
[#834]: https://github.com/rojo-rbx/rojo/pull/834
|
||||
|
|
@ -89,11 +112,19 @@
|
|||
[#843]: https://github.com/rojo-rbx/rojo/pull/843
|
||||
[#883]: https://github.com/rojo-rbx/rojo/pull/883
|
||||
[#886]: https://github.com/rojo-rbx/rojo/pull/886
|
||||
[#909]: https://github.com/rojo-rbx/rojo/pull/909
|
||||
[#911]: https://github.com/rojo-rbx/rojo/pull/911
|
||||
[#915]: https://github.com/rojo-rbx/rojo/pull/915
|
||||
[#974]: https://github.com/rojo-rbx/rojo/pull/974
|
||||
[#987]: https://github.com/rojo-rbx/rojo/pull/987
|
||||
[#988]: https://github.com/rojo-rbx/rojo/pull/988
|
||||
[#1008]: https://github.com/rojo-rbx/rojo/pull/1008
|
||||
[#1021]: https://github.com/rojo-rbx/rojo/pull/1021
|
||||
[#1027]: https://github.com/rojo-rbx/rojo/pull/1027
|
||||
|
||||
## [7.4.4] - August 22nd, 2024
|
||||
* Fixed issue with reading attributes from `Lighting` in new place files
|
||||
* `Instance.Archivable` will now default to `true` when building a project into a binary (`rbxm`/`rbxl`) file rather than `false`.
|
||||
|
||||
## [7.4.3] - August 6th, 2024
|
||||
* Fixed issue with building binary files introduced in 7.4.2
|
||||
|
|
|
|||
180
Cargo.lock
generated
180
Cargo.lock
generated
|
|
@ -17,6 +17,19 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
|
|
@ -171,6 +184,10 @@ name = "cc"
|
|||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -492,7 +509,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
|||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
|
|
@ -935,6 +952,15 @@ version = "1.0.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jod-thread"
|
||||
version = "0.1.2"
|
||||
|
|
@ -962,9 +988,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
|
|
@ -986,7 +1012,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
|||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1001,6 +1027,16 @@ version = "0.4.13"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
|
|
@ -1241,6 +1277,29 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall 0.5.10",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.14"
|
||||
|
|
@ -1310,6 +1369,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.5"
|
||||
|
|
@ -1498,10 +1563,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rbx_binary"
|
||||
version = "0.7.7"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b85057e8ff75a1ce99248200c4b3c7b481a3d52f921f1053ecd67921dcc7930"
|
||||
checksum = "9573fee5e073d7b303f475c285197fdc8179468de66ca60ee115a58fbac99296"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"log",
|
||||
"lz4",
|
||||
"profiling",
|
||||
|
|
@ -1509,23 +1575,26 @@ dependencies = [
|
|||
"rbx_reflection",
|
||||
"rbx_reflection_database",
|
||||
"thiserror",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rbx_dom_weak"
|
||||
version = "2.9.0"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcd2a17d09e46af0805f8b311a926402172b97e8d9388745c9adf8f448901841"
|
||||
checksum = "04425cf6e9376e5486f4fb35906c120d1b1b45618a490318cf563fab1fa230a9"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"rbx_types",
|
||||
"serde",
|
||||
"ustr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rbx_reflection"
|
||||
version = "4.7.0"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8118ac6021d700e8debe324af6b40ecfd2cef270a00247849dbdfeebb0802677"
|
||||
checksum = "1b6d0d62baa613556b058a5f94a53b01cf0ccde0ea327ce03056e335b982e77e"
|
||||
dependencies = [
|
||||
"rbx_types",
|
||||
"serde",
|
||||
|
|
@ -1534,9 +1603,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rbx_reflection_database"
|
||||
version = "0.2.12+roblox-638"
|
||||
version = "1.0.3+roblox-670"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e29381d675420e841f8c02db5755cbb2545ed3e13f56c539546dc58702b512a"
|
||||
checksum = "e22c05ef92528c0fb0cc580592a65ca178d3ea9beb07a1d9ca0a2503c4f3721c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"rbx_reflection",
|
||||
|
|
@ -1546,9 +1615,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rbx_types"
|
||||
version = "1.10.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e30f49b2a3bb667e4074ba73c2dfb8ca0873f610b448ccf318a240acfdec6c73"
|
||||
checksum = "78e4fdde46493def107e5f923d82e813dec9b3eef52c2f75fbad3a716023eda2"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"bitflags 1.3.2",
|
||||
|
|
@ -1561,10 +1630,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rbx_xml"
|
||||
version = "0.13.5"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b14b3027bc9ccd82e2fc854c8bcd25ed58318e570c355bf2cf63df9cdbd5ba8"
|
||||
checksum = "bb623833c31cc43bbdaeb32f5e91db8ecd63fc46e438d0d268baf9e61539cf1c"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"base64 0.13.1",
|
||||
"log",
|
||||
"rbx_dom_weak",
|
||||
|
|
@ -1582,6 +1652,15 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.4"
|
||||
|
|
@ -1752,7 +1831,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rojo"
|
||||
version = "7.5.0-prealpha"
|
||||
version = "7.5.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
|
|
@ -1896,6 +1975,12 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.1"
|
||||
|
|
@ -2393,6 +2478,19 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ustr"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18b19e258aa08450f93369cf56dd78063586adf19e92a75b338a800f799a0208"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"parking_lot",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.7.0"
|
||||
|
|
@ -2784,3 +2882,51 @@ name = "yansi"
|
|||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.15+zstd.1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
|
|
|||
18
Cargo.toml
18
Cargo.toml
|
|
@ -1,8 +1,12 @@
|
|||
[package]
|
||||
name = "rojo"
|
||||
version = "7.5.0-prealpha"
|
||||
version = "7.5.1"
|
||||
rust-version = "1.70.0"
|
||||
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
||||
authors = [
|
||||
"Lucien Greathouse <me@lpghatguy.com>",
|
||||
"Micah Reid <git@dekkonot.com>",
|
||||
"Ken Loeffler <kenloef@gmail.com>",
|
||||
]
|
||||
description = "Enables professional-grade development tools for Roblox developers"
|
||||
license = "MPL-2.0"
|
||||
homepage = "https://rojo.space"
|
||||
|
|
@ -51,11 +55,11 @@ memofs = { version = "0.3.0", path = "crates/memofs" }
|
|||
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
|
||||
# rbx_xml = { path = "../rbx-dom/rbx_xml" }
|
||||
|
||||
rbx_binary = "0.7.7"
|
||||
rbx_dom_weak = "2.9.0"
|
||||
rbx_reflection = "4.7.0"
|
||||
rbx_reflection_database = "0.2.12"
|
||||
rbx_xml = "0.13.5"
|
||||
rbx_binary = "1.0.0"
|
||||
rbx_dom_weak = "3.0.0"
|
||||
rbx_reflection = "5.0.0"
|
||||
rbx_reflection_database = "1.0.3"
|
||||
rbx_xml = "1.0.0"
|
||||
|
||||
anyhow = "1.0.80"
|
||||
backtrace = "0.3.69"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@
|
|||
name = "memofs"
|
||||
description = "Virtual filesystem with configurable backends."
|
||||
version = "0.3.0"
|
||||
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
||||
authors = [
|
||||
"Lucien Greathouse <me@lpghatguy.com>",
|
||||
"Micah Reid <git@dekkonot.com>",
|
||||
"Ken Loeffler <kenloef@gmail.com>",
|
||||
]
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
7.5.0-prealpha
|
||||
7.5.1
|
||||
|
|
@ -70,7 +70,7 @@ local function debugImpl(buffer, value, extendedForm)
|
|||
elseif valueType == "table" then
|
||||
local valueMeta = getmetatable(value)
|
||||
|
||||
if valueMeta ~= nil and valueMeta.__fmtDebug ~= nil then
|
||||
if valueMeta ~= nil and valueMeta.__fmtDebug ~= nil then
|
||||
-- This type implement's the metamethod we made up to line up with
|
||||
-- Rust's 'Debug' trait.
|
||||
|
||||
|
|
@ -242,4 +242,4 @@ return {
|
|||
debugOutputBuffer = debugOutputBuffer,
|
||||
fmt = fmt,
|
||||
debugify = debugify,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,4 +31,4 @@ function Response:json()
|
|||
return HttpService:JSONDecode(self.body)
|
||||
end
|
||||
|
||||
return Response
|
||||
return Response
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ return function()
|
|||
it("should load", function()
|
||||
require(script.Parent)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -57,4 +57,4 @@ function Log.error(template, ...)
|
|||
error(Fmt.fmt(template, ...))
|
||||
end
|
||||
|
||||
return Log
|
||||
return Log
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ return function()
|
|||
it("should load", function()
|
||||
require(script.Parent)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -188,6 +188,38 @@ types = {
|
|||
},
|
||||
|
||||
Content = {
|
||||
fromPod = function(pod): Content
|
||||
if type(pod) == "string" then
|
||||
if pod == "None" then
|
||||
return Content.none
|
||||
else
|
||||
error(`unexpected Content value '{pod}'`)
|
||||
end
|
||||
else
|
||||
local ty, value = next(pod)
|
||||
if ty == "Uri" then
|
||||
return Content.fromUri(value)
|
||||
elseif ty == "Object" then
|
||||
error("Object deserializing is not currently implemented")
|
||||
else
|
||||
error(`Unknown Content type '{ty}' (could not deserialize)`)
|
||||
end
|
||||
end
|
||||
end,
|
||||
toPod = function(roblox: Content)
|
||||
if roblox.SourceType == Enum.ContentSourceType.None then
|
||||
return "None"
|
||||
elseif roblox.SourceType == Enum.ContentSourceType.Uri then
|
||||
return { Uri = roblox.Uri }
|
||||
elseif roblox.SourceType == Enum.ContentSourceType.Object then
|
||||
error("Object serializing is not currently implemented")
|
||||
else
|
||||
error(`Unknown Content type '{roblox.SourceType} (could not serialize)`)
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
ContentId = {
|
||||
fromPod = identity,
|
||||
toPod = identity,
|
||||
},
|
||||
|
|
@ -205,6 +237,19 @@ types = {
|
|||
end,
|
||||
},
|
||||
|
||||
EnumItem = {
|
||||
fromPod = function(pod)
|
||||
return Enum[pod.type]:FromValue(pod.value)
|
||||
end,
|
||||
|
||||
toPod = function(roblox)
|
||||
return {
|
||||
type = tostring(roblox.EnumType),
|
||||
value = roblox.Value,
|
||||
}
|
||||
end,
|
||||
},
|
||||
|
||||
Faces = {
|
||||
fromPod = function(pod)
|
||||
local faces = {}
|
||||
|
|
@ -300,7 +345,12 @@ types = {
|
|||
local keypoints = {}
|
||||
|
||||
for index, keypoint in ipairs(pod.keypoints) do
|
||||
keypoints[index] = NumberSequenceKeypoint.new(keypoint.time, keypoint.value, keypoint.envelope)
|
||||
-- TODO: Add a test for NaN or Infinity values and envelopes
|
||||
-- Right now it isn't possible because it'd fail the roundtrip.
|
||||
-- It's more important that it works right now, though.
|
||||
local value = keypoint.value or 0
|
||||
local envelope = keypoint.envelope or 0
|
||||
keypoints[index] = NumberSequenceKeypoint.new(keypoint.time, value, envelope)
|
||||
end
|
||||
|
||||
return NumberSequence.new(keypoints)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Error.Kind = {
|
|||
UnknownProperty = "UnknownProperty",
|
||||
PropertyNotReadable = "PropertyNotReadable",
|
||||
PropertyNotWritable = "PropertyNotWritable",
|
||||
CannotParseBinaryString = "CannotParseBinaryString",
|
||||
Roblox = "Roblox",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@
|
|||
0.0
|
||||
]
|
||||
},
|
||||
"TestEnumItem": {
|
||||
"EnumItem": {
|
||||
"type": "Material",
|
||||
"value": 256
|
||||
}
|
||||
},
|
||||
"TestNumber": {
|
||||
"Float64": 1337.0
|
||||
},
|
||||
|
|
@ -170,9 +176,23 @@
|
|||
},
|
||||
"ty": "ColorSequence"
|
||||
},
|
||||
"Content": {
|
||||
"ContentId": {
|
||||
"value": {
|
||||
"Content": "rbxassetid://12345"
|
||||
"ContentId": "rbxassetid://12345"
|
||||
},
|
||||
"ty": "ContentId"
|
||||
},
|
||||
"Content_None": {
|
||||
"value": {
|
||||
"Content": "None"
|
||||
},
|
||||
"ty": "Content"
|
||||
},
|
||||
"Content_Uri": {
|
||||
"value": {
|
||||
"Content": {
|
||||
"Uri": "rbxasset://abc/123.rojo"
|
||||
}
|
||||
},
|
||||
"ty": "Content"
|
||||
},
|
||||
|
|
@ -182,6 +202,15 @@
|
|||
},
|
||||
"ty": "Enum"
|
||||
},
|
||||
"EnumItem": {
|
||||
"value": {
|
||||
"EnumItem": {
|
||||
"type": "Material",
|
||||
"value": 256
|
||||
}
|
||||
},
|
||||
"ty": "EnumItem"
|
||||
},
|
||||
"Faces": {
|
||||
"value": {
|
||||
"Faces": [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
local CollectionService = game:GetService("CollectionService")
|
||||
local ScriptEditorService = game:GetService("ScriptEditorService")
|
||||
|
||||
local Error = require(script.Parent.Error)
|
||||
|
||||
--- A list of `Enum.Material` values that are used for Terrain.MaterialColors
|
||||
local TERRAIN_MATERIAL_COLORS = {
|
||||
Enum.Material.Grass,
|
||||
|
|
@ -51,6 +53,10 @@ return {
|
|||
return true, instance:GetAttributes()
|
||||
end,
|
||||
write = function(instance, _, value)
|
||||
if typeof(value) ~= "table" then
|
||||
return false, Error.new(Error.Kind.CannotParseBinaryString)
|
||||
end
|
||||
|
||||
local existing = instance:GetAttributes()
|
||||
local didAllWritesSucceed = true
|
||||
|
||||
|
|
@ -160,9 +166,14 @@ return {
|
|||
return true, colors
|
||||
end,
|
||||
write = function(instance: Terrain, _, value: { [Enum.Material]: Color3 })
|
||||
if typeof(value) ~= "table" then
|
||||
return false, Error.new(Error.Kind.CannotParseBinaryString)
|
||||
end
|
||||
|
||||
for material, color in value do
|
||||
instance:SetMaterialColor(material, color)
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -45,14 +45,7 @@ end
|
|||
|
||||
local function rejectWrongPlaceId(infoResponseBody)
|
||||
if infoResponseBody.expectedPlaceIds ~= nil then
|
||||
local foundId = false
|
||||
|
||||
for _, id in ipairs(infoResponseBody.expectedPlaceIds) do
|
||||
if id == game.PlaceId then
|
||||
foundId = true
|
||||
break
|
||||
end
|
||||
end
|
||||
local foundId = table.find(infoResponseBody.expectedPlaceIds, game.PlaceId)
|
||||
|
||||
if not foundId then
|
||||
local idList = {}
|
||||
|
|
@ -62,10 +55,30 @@ local function rejectWrongPlaceId(infoResponseBody)
|
|||
|
||||
local message = (
|
||||
"Found a Rojo server, but its project is set to only be used with a specific list of places."
|
||||
.. "\nYour place ID is %s, but needs to be one of these:"
|
||||
.. "\nYour place ID is %u, but needs to be one of these:"
|
||||
.. "\n%s"
|
||||
.. "\n\nTo change this list, edit 'servePlaceIds' in your .project.json file."
|
||||
):format(tostring(game.PlaceId), table.concat(idList, "\n"))
|
||||
):format(game.PlaceId, table.concat(idList, "\n"))
|
||||
|
||||
return Promise.reject(message)
|
||||
end
|
||||
end
|
||||
|
||||
if infoResponseBody.unexpectedPlaceIds ~= nil then
|
||||
local foundId = table.find(infoResponseBody.unexpectedPlaceIds, game.PlaceId)
|
||||
|
||||
if foundId then
|
||||
local idList = {}
|
||||
for _, id in ipairs(infoResponseBody.unexpectedPlaceIds) do
|
||||
table.insert(idList, "- " .. tostring(id))
|
||||
end
|
||||
|
||||
local message = (
|
||||
"Found a Rojo server, but its project is set to not be used with a specific list of places."
|
||||
.. "\nYour place ID is %u, but needs to not be one of these:"
|
||||
.. "\n%s"
|
||||
.. "\n\nTo change this list, edit 'blockedPlaceIds' in your .project.json file."
|
||||
):format(game.PlaceId, table.concat(idList, "\n"))
|
||||
|
||||
return Promise.reject(message)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ local invariant = require(script.Parent.Parent.invariant)
|
|||
|
||||
local decodeValue = require(script.Parent.decodeValue)
|
||||
local reify = require(script.Parent.reify)
|
||||
local reifyInstance, applyDeferredRefs = reify.reifyInstance, reify.applyDeferredRefs
|
||||
local setProperty = require(script.Parent.setProperty)
|
||||
|
||||
local function applyPatch(instanceMap, patch)
|
||||
|
|
@ -29,6 +30,11 @@ local function applyPatch(instanceMap, patch)
|
|||
-- Tracks any portions of the patch that could not be applied to the DOM.
|
||||
local unappliedPatch = PatchSet.newEmpty()
|
||||
|
||||
-- Contains a list of all of the ref properties that we'll need to assign.
|
||||
-- It is imperative that refs are assigned after all instances are created
|
||||
-- to ensure that referents can be mapped to instances correctly.
|
||||
local deferredRefs = {}
|
||||
|
||||
for _, removedIdOrInstance in ipairs(patch.removed) do
|
||||
local removeInstanceSuccess = pcall(function()
|
||||
if Types.RbxId(removedIdOrInstance) then
|
||||
|
|
@ -78,7 +84,7 @@ local function applyPatch(instanceMap, patch)
|
|||
)
|
||||
end
|
||||
|
||||
local failedToReify = reify(instanceMap, patch.added, id, parentInstance)
|
||||
local failedToReify = reifyInstance(deferredRefs, instanceMap, patch.added, id, parentInstance)
|
||||
|
||||
if not PatchSet.isEmpty(failedToReify) then
|
||||
Log.debug("Failed to reify as part of applying a patch: {:#?}", failedToReify)
|
||||
|
|
@ -143,7 +149,7 @@ local function applyPatch(instanceMap, patch)
|
|||
[update.id] = mockVirtualInstance,
|
||||
}
|
||||
|
||||
local failedToReify = reify(instanceMap, mockAdded, update.id, instance.Parent)
|
||||
local failedToReify = reifyInstance(deferredRefs, instanceMap, mockAdded, update.id, instance.Parent)
|
||||
|
||||
local newInstance = instanceMap.fromIds[update.id]
|
||||
|
||||
|
|
@ -206,6 +212,18 @@ local function applyPatch(instanceMap, patch)
|
|||
|
||||
if update.changedProperties ~= nil then
|
||||
for propertyName, propertyValue in pairs(update.changedProperties) do
|
||||
-- Because refs may refer to instances that we haven't constructed yet,
|
||||
-- we defer applying any ref properties until all instances are created.
|
||||
if next(propertyValue) == "Ref" then
|
||||
table.insert(deferredRefs, {
|
||||
id = update.id,
|
||||
instance = instance,
|
||||
propertyName = propertyName,
|
||||
virtualValue = propertyValue,
|
||||
})
|
||||
continue
|
||||
end
|
||||
|
||||
local decodeSuccess, decodedValue = decodeValue(propertyValue, instanceMap)
|
||||
if not decodeSuccess then
|
||||
unappliedUpdate.changedProperties[propertyName] = propertyValue
|
||||
|
|
@ -230,6 +248,8 @@ local function applyPatch(instanceMap, patch)
|
|||
ChangeHistoryService:FinishRecording(historyRecording, Enum.FinishRecordingOperation.Commit)
|
||||
end
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
return unappliedPatch
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,24 @@ local function diff(instanceMap, virtualInstances, rootId)
|
|||
|
||||
if getProperySuccess then
|
||||
local existingValue = existingValueOrErr
|
||||
local decodeSuccess, decodedValue = decodeValue(virtualValue, instanceMap)
|
||||
local decodeSuccess, decodedValue
|
||||
|
||||
-- If `virtualValue` is a ref then instead of decoding it to an instance,
|
||||
-- we change `existingValue` to be a ref. This is because `virtualValue`
|
||||
-- may point to an Instance which doesn't exist yet and therefore
|
||||
-- decoding it may throw an error.
|
||||
if next(virtualValue) == "Ref" then
|
||||
decodeSuccess, decodedValue = true, virtualValue
|
||||
|
||||
if existingValue and typeof(existingValue) == "Instance" then
|
||||
local existingValueRef = instanceMap.fromInstances[existingValue]
|
||||
if existingValueRef then
|
||||
existingValue = { Ref = existingValueRef }
|
||||
end
|
||||
end
|
||||
else
|
||||
decodeSuccess, decodedValue = decodeValue(virtualValue, instanceMap)
|
||||
end
|
||||
|
||||
if decodeSuccess then
|
||||
if not trueEquals(existingValue, decodedValue) then
|
||||
|
|
|
|||
|
|
@ -7,26 +7,6 @@ local PatchSet = require(script.Parent.Parent.PatchSet)
|
|||
local setProperty = require(script.Parent.setProperty)
|
||||
local decodeValue = require(script.Parent.decodeValue)
|
||||
|
||||
local reifyInner, applyDeferredRefs
|
||||
|
||||
local function reify(instanceMap, virtualInstances, rootId, parentInstance)
|
||||
-- Create an empty patch that will be populated with any parts of this reify
|
||||
-- that could not happen, like instances that couldn't be created and
|
||||
-- properties that could not be assigned.
|
||||
local unappliedPatch = PatchSet.newEmpty()
|
||||
|
||||
-- Contains a list of all of the ref properties that we'll need to assign
|
||||
-- after all instances are created. We apply refs in a second pass, after
|
||||
-- we create as many instances as we can, so that we ensure that referents
|
||||
-- can be mapped to instances correctly.
|
||||
local deferredRefs = {}
|
||||
|
||||
reifyInner(instanceMap, virtualInstances, rootId, parentInstance, unappliedPatch, deferredRefs)
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
return unappliedPatch
|
||||
end
|
||||
|
||||
--[[
|
||||
Add the given ID and all of its descendants in virtualInstances to the given
|
||||
PatchSet, marked for addition.
|
||||
|
|
@ -40,10 +20,21 @@ local function addAllToPatch(patchSet, virtualInstances, id)
|
|||
end
|
||||
end
|
||||
|
||||
function reifyInstance(deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
|
||||
-- Create an empty patch that will be populated with any parts of this reify
|
||||
-- that could not happen, like instances that couldn't be created and
|
||||
-- properties that could not be assigned.
|
||||
local unappliedPatch = PatchSet.newEmpty()
|
||||
|
||||
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
|
||||
|
||||
return unappliedPatch
|
||||
end
|
||||
|
||||
--[[
|
||||
Inner function that defines the core routine.
|
||||
]]
|
||||
function reifyInner(instanceMap, virtualInstances, id, parentInstance, unappliedPatch, deferredRefs)
|
||||
function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, id, parentInstance)
|
||||
local virtualInstance = virtualInstances[id]
|
||||
|
||||
if virtualInstance == nil then
|
||||
|
|
@ -102,7 +93,7 @@ function reifyInner(instanceMap, virtualInstances, id, parentInstance, unapplied
|
|||
end
|
||||
|
||||
for _, childId in ipairs(virtualInstance.Children) do
|
||||
reifyInner(instanceMap, virtualInstances, childId, instance, unappliedPatch, deferredRefs)
|
||||
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, childId, instance)
|
||||
end
|
||||
|
||||
instance.Parent = parentInstance
|
||||
|
|
@ -143,6 +134,7 @@ function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
|||
end
|
||||
|
||||
local targetInstance = instanceMap.fromIds[refId]
|
||||
|
||||
if targetInstance == nil then
|
||||
markFailed(entry.id, entry.propertyName, entry.virtualValue)
|
||||
continue
|
||||
|
|
@ -155,4 +147,7 @@ function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
|||
end
|
||||
end
|
||||
|
||||
return reify
|
||||
return {
|
||||
reifyInstance = reifyInstance,
|
||||
applyDeferredRefs = applyDeferredRefs,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
return function()
|
||||
local reify = require(script.Parent.reify)
|
||||
local reifyInstance, applyDeferredRefs = reify.reifyInstance, reify.applyDeferredRefs
|
||||
|
||||
local PatchSet = require(script.Parent.Parent.PatchSet)
|
||||
local InstanceMap = require(script.Parent.Parent.InstanceMap)
|
||||
|
|
@ -20,7 +21,11 @@ return function()
|
|||
|
||||
it("should throw when given a bogus ID", function()
|
||||
expect(function()
|
||||
reify(InstanceMap.new(), {}, "Hi, mom!", game)
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, {}, "Hi, mom!", game)
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
|
|
@ -34,8 +39,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT", nil)
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT", nil)
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(instanceMap:size() == 0, "expected instanceMap to be empty")
|
||||
|
||||
|
|
@ -60,8 +68,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||
|
||||
|
|
@ -90,8 +101,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||
|
||||
|
|
@ -122,8 +136,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
expect(size(unappliedPatch.added)).to.equal(1)
|
||||
expect(unappliedPatch.added["CHILD"]).to.equal(virtualInstances["CHILD"])
|
||||
|
|
@ -153,8 +170,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
local instance = instanceMap.fromIds["ROOT"]
|
||||
expect(instance.ClassName).to.equal("StringValue")
|
||||
|
|
@ -196,8 +216,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||
|
||||
|
|
@ -223,13 +246,16 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
|
||||
local existing = Instance.new("Folder")
|
||||
existing.Name = "Existing"
|
||||
instanceMap:insert("EXISTING", existing)
|
||||
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||
|
||||
|
|
@ -268,8 +294,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||
|
||||
|
|
@ -307,8 +336,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
|
||||
|
||||
|
|
@ -332,8 +364,11 @@ return function()
|
|||
},
|
||||
}
|
||||
|
||||
local deferredRefs = {}
|
||||
local instanceMap = InstanceMap.new()
|
||||
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
|
||||
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
|
||||
|
||||
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
|
||||
|
||||
assert(not PatchSet.hasRemoves(unappliedPatch), "expected no removes")
|
||||
assert(not PatchSet.hasAdditions(unappliedPatch), "expected no additions")
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ expression: contents
|
|||
<Item class="Model" referent="0">
|
||||
<Properties>
|
||||
<string name="Name">init_meta_class_name</string>
|
||||
<bool name="NeedsPivotMigration">false</bool>
|
||||
</Properties>
|
||||
</Item>
|
||||
</roblox>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/build.rs
|
||||
expression: contents
|
||||
|
||||
---
|
||||
<roblox version="4">
|
||||
<Item class="Folder" referent="0">
|
||||
|
|
@ -25,6 +24,7 @@ expression: contents
|
|||
<R21>0</R21>
|
||||
<R22>1</R22>
|
||||
</CoordinateFrame>
|
||||
<bool name="NeedsPivotMigration">false</bool>
|
||||
<Ref name="PrimaryPart">null</Ref>
|
||||
<BinaryString name="Tags"></BinaryString>
|
||||
</Properties>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/build.rs
|
||||
expression: contents
|
||||
|
||||
---
|
||||
<roblox version="4">
|
||||
<Item class="DataModel" referent="0">
|
||||
|
|
@ -22,6 +21,7 @@ expression: contents
|
|||
<Item class="Workspace" referent="2">
|
||||
<Properties>
|
||||
<string name="Name">Workspace</string>
|
||||
<bool name="NeedsPivotMigration">false</bool>
|
||||
</Properties>
|
||||
<Item class="BoolValue" referent="3">
|
||||
<Properties>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
||||
|
||||
---
|
||||
instances:
|
||||
id-2:
|
||||
|
|
@ -22,7 +21,8 @@ instances:
|
|||
ignoreUnknownInstances: false
|
||||
Name: test
|
||||
Parent: id-2
|
||||
Properties: {}
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
messageCursor: 1
|
||||
sessionId: id-1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
||||
|
||||
---
|
||||
messageCursor: 1
|
||||
messages:
|
||||
|
|
@ -14,8 +13,9 @@ messages:
|
|||
ignoreUnknownInstances: false
|
||||
Name: test
|
||||
Parent: id-2
|
||||
Properties: {}
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
removed: []
|
||||
updated: []
|
||||
sessionId: id-1
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
||||
---
|
||||
instances:
|
||||
id-2:
|
||||
Children:
|
||||
- id-3
|
||||
ClassName: DataModel
|
||||
Id: id-2
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: pivot_migration
|
||||
Parent: "00000000000000000000000000000000"
|
||||
Properties: {}
|
||||
id-3:
|
||||
Children:
|
||||
- id-4
|
||||
- id-5
|
||||
- id-6
|
||||
ClassName: Workspace
|
||||
Id: id-3
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: Workspace
|
||||
Parent: id-2
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-4:
|
||||
Children: []
|
||||
ClassName: Model
|
||||
Id: id-4
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: Model
|
||||
Parent: id-3
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-5:
|
||||
Children: []
|
||||
ClassName: Tool
|
||||
Id: id-5
|
||||
Metadata:
|
||||
ignoreUnknownInstances: false
|
||||
Name: Tool
|
||||
Parent: id-3
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-6:
|
||||
Children: []
|
||||
ClassName: Actor
|
||||
Id: id-6
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: Actor
|
||||
Parent: id-3
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
messageCursor: 1
|
||||
sessionId: id-1
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
||||
---
|
||||
messageCursor: 1
|
||||
messages:
|
||||
- added:
|
||||
id-6:
|
||||
Children: []
|
||||
ClassName: Actor
|
||||
Id: id-6
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: Actor
|
||||
Parent: id-3
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
removed: []
|
||||
updated:
|
||||
- changedClassName: ~
|
||||
changedMetadata:
|
||||
ignoreUnknownInstances: true
|
||||
changedName: ~
|
||||
changedProperties: {}
|
||||
id: id-3
|
||||
sessionId: id-1
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 316
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 335
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 351
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
|
||||
---
|
||||
instances:
|
||||
id-2:
|
||||
Children:
|
||||
- id-3
|
||||
ClassName: DataModel
|
||||
Id: id-2
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: pivot_migration
|
||||
Parent: "00000000000000000000000000000000"
|
||||
Properties: {}
|
||||
id-3:
|
||||
Children:
|
||||
- id-4
|
||||
- id-5
|
||||
ClassName: Workspace
|
||||
Id: id-3
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: Workspace
|
||||
Parent: id-2
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-4:
|
||||
Children: []
|
||||
ClassName: Model
|
||||
Id: id-4
|
||||
Metadata:
|
||||
ignoreUnknownInstances: true
|
||||
Name: Model
|
||||
Parent: id-3
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-5:
|
||||
Children: []
|
||||
ClassName: Tool
|
||||
Id: id-5
|
||||
Metadata:
|
||||
ignoreUnknownInstances: false
|
||||
Name: Tool
|
||||
Parent: id-3
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
messageCursor: 0
|
||||
sessionId: id-1
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
placeId: ~
|
||||
projectName: pivot_migration
|
||||
protocolVersion: 4
|
||||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
@ -31,6 +31,8 @@ instances:
|
|||
Attributes:
|
||||
Rojo_Target_PrimaryPart:
|
||||
String: project target
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
PrimaryPart:
|
||||
Ref: id-9
|
||||
id-2:
|
||||
|
|
@ -55,7 +57,9 @@ instances:
|
|||
ignoreUnknownInstances: true
|
||||
Name: Workspace
|
||||
Parent: id-2
|
||||
Properties: {}
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-4:
|
||||
Children: []
|
||||
ClassName: ObjectValue
|
||||
|
|
@ -124,6 +128,8 @@ instances:
|
|||
Attributes:
|
||||
Rojo_Target_PrimaryPart:
|
||||
String: model target 2
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
PrimaryPart:
|
||||
Ref: id-7
|
||||
id-9:
|
||||
|
|
@ -138,4 +144,3 @@ instances:
|
|||
Properties: {}
|
||||
messageCursor: 1
|
||||
sessionId: id-1
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ instances:
|
|||
ignoreUnknownInstances: true
|
||||
Name: Workspace
|
||||
Parent: id-2
|
||||
Properties: {}
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-4:
|
||||
Children: []
|
||||
ClassName: ObjectValue
|
||||
|
|
@ -104,6 +106,8 @@ instances:
|
|||
Attributes:
|
||||
Rojo_Target_PrimaryPart:
|
||||
String: model target
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
PrimaryPart:
|
||||
Ref: id-7
|
||||
id-9:
|
||||
|
|
@ -118,4 +122,3 @@ instances:
|
|||
Properties: {}
|
||||
messageCursor: 0
|
||||
sessionId: id-1
|
||||
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ instances:
|
|||
ignoreUnknownInstances: true
|
||||
Name: Workspace
|
||||
Parent: id-2
|
||||
Properties: {}
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-4:
|
||||
Children: []
|
||||
ClassName: ObjectValue
|
||||
|
|
@ -104,8 +106,12 @@ instances:
|
|||
Attributes:
|
||||
Rojo_Target_PrimaryPart:
|
||||
String: model target
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
PrimaryPart:
|
||||
Ref: id-7
|
||||
Scale:
|
||||
Float32: 1
|
||||
id-9:
|
||||
Children:
|
||||
- id-10
|
||||
|
|
@ -116,5 +122,5 @@ instances:
|
|||
Name: ProjectTarget
|
||||
Parent: id-3
|
||||
Properties: {}
|
||||
messageCursor: 0
|
||||
messageCursor: 1
|
||||
sessionId: id-1
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ instances:
|
|||
ignoreUnknownInstances: true
|
||||
Name: Workspace
|
||||
Parent: id-2
|
||||
Properties: {}
|
||||
Properties:
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
id-4:
|
||||
Children: []
|
||||
ClassName: ObjectValue
|
||||
|
|
@ -104,6 +106,8 @@ instances:
|
|||
Attributes:
|
||||
Rojo_Target_PrimaryPart:
|
||||
String: model target
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
PrimaryPart:
|
||||
Ref: id-7
|
||||
id-9:
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
|
||||
---
|
||||
messageCursor: 1
|
||||
messages:
|
||||
- added: {}
|
||||
removed: []
|
||||
updated:
|
||||
- changedClassName: ~
|
||||
changedMetadata: ~
|
||||
changedName: ~
|
||||
changedProperties:
|
||||
Scale:
|
||||
Float32: 1
|
||||
id: id-8
|
||||
sessionId: id-1
|
||||
|
|
@ -10,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ messages:
|
|||
Attributes:
|
||||
Rojo_Target_PrimaryPart:
|
||||
String: project target
|
||||
NeedsPivotMigration:
|
||||
Bool: false
|
||||
PrimaryPart:
|
||||
Ref: id-9
|
||||
removed: []
|
||||
|
|
@ -43,4 +45,3 @@ messages:
|
|||
PrimaryPart: ~
|
||||
id: id-8
|
||||
sessionId: id-1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
expression: redactions.redacted_yaml(info)
|
||||
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
gameId: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 265
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 281
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 297
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,4 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: tests/tests/serve.rs
|
||||
assertion_line: 383
|
||||
expression: redactions.redacted_yaml(info)
|
||||
---
|
||||
expectedPlaceIds: ~
|
||||
|
|
@ -11,3 +10,4 @@ protocolVersion: 4
|
|||
rootInstanceId: id-2
|
||||
serverVersion: "[server-version]"
|
||||
sessionId: id-1
|
||||
unexpectedPlaceIds: ~
|
||||
|
|
|
|||
3
rojo-test/serve-tests/pivot_migration/Tool.model.json
Normal file
3
rojo-test/serve-tests/pivot_migration/Tool.model.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"className": "Tool"
|
||||
}
|
||||
14
rojo-test/serve-tests/pivot_migration/default.project.json
Normal file
14
rojo-test/serve-tests/pivot_migration/default.project.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "pivot_migration",
|
||||
"tree": {
|
||||
"$className": "DataModel",
|
||||
"Workspace": {
|
||||
"Model": {
|
||||
"$className": "Model"
|
||||
},
|
||||
"Tool": {
|
||||
"$path": "Tool.model.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ use clap::Parser;
|
|||
use fs_err::File;
|
||||
use memofs::Vfs;
|
||||
use rayon::prelude::*;
|
||||
use rbx_dom_weak::types::Ref;
|
||||
use rbx_dom_weak::{types::Ref, Ustr};
|
||||
use serde::Serialize;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ const PATH_STRIP_FAILED_ERR: &str = "Failed to create relative paths for project
|
|||
#[serde(rename_all = "camelCase")]
|
||||
struct SourcemapNode<'a> {
|
||||
name: &'a str,
|
||||
class_name: &'a str,
|
||||
class_name: Ustr,
|
||||
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
file_paths: Vec<PathBuf>,
|
||||
|
|
@ -113,7 +113,7 @@ fn filter_nothing(_instance: &InstanceWithMeta) -> bool {
|
|||
|
||||
fn filter_non_scripts(instance: &InstanceWithMeta) -> bool {
|
||||
matches!(
|
||||
instance.class_name(),
|
||||
instance.class_name().as_str(),
|
||||
"Script" | "LocalScript" | "ModuleScript"
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use std::{
|
|||
};
|
||||
|
||||
use memofs::Vfs;
|
||||
use rbx_dom_weak::{Ustr, UstrMap};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
@ -78,6 +79,14 @@ pub struct Project {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub serve_place_ids: Option<HashSet<u64>>,
|
||||
|
||||
/// If specified, contains a set of place IDs that this project is
|
||||
/// not compatible with when doing live sync.
|
||||
///
|
||||
/// This setting is intended to help prevent syncing a Rojo project into the
|
||||
/// wrong Roblox place.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub blocked_place_ids: Option<HashSet<u64>>,
|
||||
|
||||
/// If specified, sets the current place's place ID when connecting to the
|
||||
/// Rojo server from Roblox Studio.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -310,7 +319,7 @@ pub struct ProjectNode {
|
|||
/// `$className` CANNOT be set if `$path` is set and the instance described
|
||||
/// by that path has a ClassName other than Folder.
|
||||
#[serde(rename = "$className", skip_serializing_if = "Option::is_none")]
|
||||
pub class_name: Option<String>,
|
||||
pub class_name: Option<Ustr>,
|
||||
|
||||
/// If set, defines an ID for the described Instance that can be used
|
||||
/// to refer to it for the purpose of referent properties.
|
||||
|
|
@ -329,7 +338,7 @@ pub struct ProjectNode {
|
|||
default,
|
||||
skip_serializing_if = "HashMap::is_empty"
|
||||
)]
|
||||
pub properties: HashMap<String, UnresolvedValue>,
|
||||
pub properties: UstrMap<UnresolvedValue>,
|
||||
|
||||
#[serde(
|
||||
rename = "$attributes",
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::borrow::Borrow;
|
|||
|
||||
use anyhow::{bail, format_err};
|
||||
use rbx_dom_weak::types::{
|
||||
Attributes, CFrame, Color3, Content, Enum, Font, MaterialColors, Matrix3, Tags, Variant,
|
||||
VariantType, Vector2, Vector3,
|
||||
Attributes, CFrame, Color3, Content, ContentId, Enum, Font, MaterialColors, Matrix3, Tags,
|
||||
Variant, VariantType, Vector2, Vector3,
|
||||
};
|
||||
use rbx_reflection::{DataType, PropertyDescriptor};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -116,6 +116,9 @@ impl AmbiguousValue {
|
|||
(VariantType::Content, AmbiguousValue::String(value)) => {
|
||||
Ok(Content::from(value).into())
|
||||
}
|
||||
(VariantType::ContentId, AmbiguousValue::String(value)) => {
|
||||
Ok(ContentId::from(value).into())
|
||||
}
|
||||
|
||||
(VariantType::Vector2, AmbiguousValue::Array2(value)) => {
|
||||
Ok(Vector2::new(value[0] as f32, value[1] as f32).into())
|
||||
|
|
@ -275,10 +278,20 @@ mod test {
|
|||
Variant::String("Hello!".into()),
|
||||
);
|
||||
|
||||
// String literals can also turn into Content
|
||||
// String literals can also turn into ContentId
|
||||
assert_eq!(
|
||||
resolve("Sky", "MoonTextureId", "\"rbxassetid://12345\""),
|
||||
Variant::Content("rbxassetid://12345".into()),
|
||||
Variant::ContentId("rbxassetid://12345".into()),
|
||||
);
|
||||
|
||||
// String literals can turn into Content!
|
||||
assert_eq!(
|
||||
resolve(
|
||||
"MeshPart",
|
||||
"MeshContent",
|
||||
"\"rbxasset://totally-a-real-uri.tiff\""
|
||||
),
|
||||
Variant::Content("rbxasset://totally-a-real-uri.tiff".into())
|
||||
);
|
||||
|
||||
// What about BinaryString values? For forward-compatibility reasons, we
|
||||
|
|
|
|||
|
|
@ -208,6 +208,10 @@ impl ServeSession {
|
|||
self.root_project.serve_place_ids.as_ref()
|
||||
}
|
||||
|
||||
pub fn blocked_place_ids(&self) -> Option<&HashSet<u64>> {
|
||||
self.root_project.blocked_place_ids.as_ref()
|
||||
}
|
||||
|
||||
pub fn serve_address(&self) -> Option<IpAddr> {
|
||||
self.root_project.serve_address
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
//! Defines the structure of an instance snapshot.
|
||||
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant},
|
||||
Instance, WeakDom,
|
||||
ustr, AHashMap, HashMapExt as _, Instance, Ustr, UstrMap, WeakDom,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -27,10 +27,10 @@ pub struct InstanceSnapshot {
|
|||
pub name: Cow<'static, str>,
|
||||
|
||||
/// Corresponds to the ClassName property of the instance.
|
||||
pub class_name: Cow<'static, str>,
|
||||
pub class_name: Ustr,
|
||||
|
||||
/// All other properties of the instance, weakly-typed.
|
||||
pub properties: HashMap<String, Variant>,
|
||||
pub properties: UstrMap<Variant>,
|
||||
|
||||
/// The children of the instance represented as more snapshots.
|
||||
///
|
||||
|
|
@ -44,8 +44,8 @@ impl InstanceSnapshot {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: InstanceMetadata::default(),
|
||||
name: Cow::Borrowed("DEFAULT"),
|
||||
class_name: Cow::Borrowed("DEFAULT"),
|
||||
properties: HashMap::new(),
|
||||
class_name: ustr("DEFAULT"),
|
||||
properties: UstrMap::new(),
|
||||
children: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -57,23 +57,23 @@ impl InstanceSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn class_name(self, class_name: impl Into<String>) -> Self {
|
||||
pub fn class_name<S: Into<Ustr>>(self, class_name: S) -> Self {
|
||||
Self {
|
||||
class_name: Cow::Owned(class_name.into()),
|
||||
class_name: class_name.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn property<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
K: Into<String>,
|
||||
K: Into<Ustr>,
|
||||
V: Into<Variant>,
|
||||
{
|
||||
self.properties.insert(key.into(), value.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn properties(self, properties: impl Into<HashMap<String, Variant>>) -> Self {
|
||||
pub fn properties(self, properties: impl Into<UstrMap<Variant>>) -> Self {
|
||||
Self {
|
||||
properties: properties.into(),
|
||||
..self
|
||||
|
|
@ -107,7 +107,7 @@ impl InstanceSnapshot {
|
|||
Self::from_raw_tree(&mut raw_tree, id)
|
||||
}
|
||||
|
||||
fn from_raw_tree(raw_tree: &mut HashMap<Ref, Instance>, id: Ref) -> Self {
|
||||
fn from_raw_tree(raw_tree: &mut AHashMap<Ref, Instance>, id: Ref) -> Self {
|
||||
let instance = raw_tree
|
||||
.remove(&id)
|
||||
.expect("instance did not exist in tree");
|
||||
|
|
@ -122,7 +122,7 @@ impl InstanceSnapshot {
|
|||
snapshot_id: id,
|
||||
metadata: InstanceMetadata::default(),
|
||||
name: Cow::Owned(instance.name),
|
||||
class_name: Cow::Owned(instance.class),
|
||||
class_name: instance.class,
|
||||
properties: instance.properties,
|
||||
children,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
//! Defines the data structures used for describing instance patches.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rbx_dom_weak::types::{Ref, Variant};
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant},
|
||||
HashMapExt as _, Ustr, UstrMap,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{InstanceMetadata, InstanceSnapshot};
|
||||
|
|
@ -41,11 +42,11 @@ pub struct PatchAdd {
|
|||
pub struct PatchUpdate {
|
||||
pub id: Ref,
|
||||
pub changed_name: Option<String>,
|
||||
pub changed_class_name: Option<String>,
|
||||
pub changed_class_name: Option<Ustr>,
|
||||
|
||||
/// Contains all changed properties. If a property is assigned to `None`,
|
||||
/// then that property has been removed.
|
||||
pub changed_properties: HashMap<String, Option<Variant>>,
|
||||
pub changed_properties: UstrMap<Option<Variant>>,
|
||||
|
||||
/// Changed Rojo-specific metadata, if any of it changed.
|
||||
pub changed_metadata: Option<InstanceMetadata>,
|
||||
|
|
@ -88,8 +89,8 @@ pub struct AppliedPatchUpdate {
|
|||
|
||||
// TODO: Store previous values in order to detect application conflicts
|
||||
pub changed_name: Option<String>,
|
||||
pub changed_class_name: Option<String>,
|
||||
pub changed_properties: HashMap<String, Option<Variant>>,
|
||||
pub changed_class_name: Option<Ustr>,
|
||||
pub changed_properties: UstrMap<Option<Variant>>,
|
||||
pub changed_metadata: Option<InstanceMetadata>,
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ impl AppliedPatchUpdate {
|
|||
id,
|
||||
changed_name: None,
|
||||
changed_class_name: None,
|
||||
changed_properties: HashMap::new(),
|
||||
changed_properties: UstrMap::new(),
|
||||
changed_metadata: None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ use std::{
|
|||
mem::take,
|
||||
};
|
||||
|
||||
use rbx_dom_weak::types::{Ref, Variant};
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant},
|
||||
ustr, Ustr,
|
||||
};
|
||||
|
||||
use super::{
|
||||
patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate},
|
||||
|
|
@ -76,7 +79,7 @@ struct PatchApplyContext {
|
|||
/// Tracks all ref properties that were specified using attributes. This has
|
||||
/// to be handled after everything else is done just like normal referent
|
||||
/// properties.
|
||||
attribute_refs_to_rewrite: MultiMap<Ref, (String, String)>,
|
||||
attribute_refs_to_rewrite: MultiMap<Ref, (Ustr, String)>,
|
||||
|
||||
/// The current applied patch result, describing changes made to the tree.
|
||||
applied_patch_set: AppliedPatchSet,
|
||||
|
|
@ -193,7 +196,7 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
|
|||
}
|
||||
|
||||
if let Some(class_name) = patch.changed_class_name {
|
||||
*instance.class_name_mut() = class_name.clone();
|
||||
instance.set_class_name(class_name);
|
||||
applied_patch.changed_class_name = Some(class_name);
|
||||
}
|
||||
|
||||
|
|
@ -219,10 +222,10 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
|
|||
|
||||
instance
|
||||
.properties_mut()
|
||||
.insert(key.clone(), Variant::Ref(new_referent));
|
||||
.insert(key, Variant::Ref(new_referent));
|
||||
}
|
||||
Some(ref value) => {
|
||||
instance.properties_mut().insert(key.clone(), value.clone());
|
||||
instance.properties_mut().insert(key, value.clone());
|
||||
}
|
||||
None => {
|
||||
instance.properties_mut().remove(&key);
|
||||
|
|
@ -247,7 +250,7 @@ fn defer_ref_properties(tree: &mut RojoTree, id: Ref, context: &mut PatchApplyCo
|
|||
let instance = tree
|
||||
.get_instance(id)
|
||||
.expect("Instances should exist when calculating deferred refs");
|
||||
let attributes = match instance.properties().get("Attributes") {
|
||||
let attributes = match instance.properties().get(&ustr("Attributes")) {
|
||||
Some(Variant::Attributes(attrs)) => attrs,
|
||||
_ => return,
|
||||
};
|
||||
|
|
@ -275,12 +278,12 @@ fn defer_ref_properties(tree: &mut RojoTree, id: Ref, context: &mut PatchApplyCo
|
|||
if let Variant::String(prop_value) = attr_value {
|
||||
context
|
||||
.attribute_refs_to_rewrite
|
||||
.insert(id, (prop_name.to_owned(), prop_value.clone()));
|
||||
.insert(id, (ustr(prop_name), prop_value.clone()));
|
||||
} else if let Variant::BinaryString(prop_value) = attr_value {
|
||||
if let Ok(str) = std::str::from_utf8(prop_value.as_ref()) {
|
||||
context
|
||||
.attribute_refs_to_rewrite
|
||||
.insert(id, (prop_name.to_owned(), str.to_string()));
|
||||
.insert(id, (ustr(prop_name), str.to_string()));
|
||||
} else {
|
||||
log::error!("IDs specified by referent property attributes must be valid UTF-8 strings.")
|
||||
}
|
||||
|
|
@ -304,7 +307,7 @@ mod test {
|
|||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rbx_dom_weak::types::Variant;
|
||||
use rbx_dom_weak::{types::Variant, UstrMap};
|
||||
|
||||
use super::super::PatchAdd;
|
||||
|
||||
|
|
@ -320,8 +323,8 @@ mod test {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("Foo"),
|
||||
class_name: Cow::Borrowed("Bar"),
|
||||
properties: [("Baz".to_owned(), Variant::Int32(5))].into(),
|
||||
class_name: ustr("Bar"),
|
||||
properties: UstrMap::from_iter([(ustr("Baz"), Variant::Int32(5))]),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
||||
|
|
@ -340,7 +343,7 @@ mod test {
|
|||
let child_instance = tree.get_instance(child_id).unwrap();
|
||||
|
||||
assert_eq!(child_instance.name(), &snapshot.name);
|
||||
assert_eq!(child_instance.class_name(), &snapshot.class_name);
|
||||
assert_eq!(child_instance.class_name(), snapshot.class_name);
|
||||
assert_eq!(child_instance.properties(), &snapshot.properties);
|
||||
assert!(child_instance.children().is_empty());
|
||||
}
|
||||
|
|
@ -363,16 +366,15 @@ mod test {
|
|||
let patch = PatchUpdate {
|
||||
id: root_id,
|
||||
changed_name: Some("Foo".to_owned()),
|
||||
changed_class_name: Some("NewClassName".to_owned()),
|
||||
changed_properties: [
|
||||
changed_class_name: Some(ustr("NewClassName")),
|
||||
changed_properties: UstrMap::from_iter([
|
||||
// The value of Foo has changed
|
||||
("Foo".to_owned(), Some(Variant::Int32(8))),
|
||||
(ustr("Foo"), Some(Variant::Int32(8))),
|
||||
// Bar has been deleted
|
||||
("Bar".to_owned(), None),
|
||||
(ustr("Bar"), None),
|
||||
// Baz has been added
|
||||
("Baz".to_owned(), Some(Variant::Int32(10))),
|
||||
]
|
||||
.into(),
|
||||
(ustr("Baz"), Some(Variant::Int32(10))),
|
||||
]),
|
||||
changed_metadata: None,
|
||||
};
|
||||
|
||||
|
|
@ -383,12 +385,11 @@ mod test {
|
|||
|
||||
apply_patch_set(&mut tree, patch_set);
|
||||
|
||||
let expected_properties = [
|
||||
("Foo".to_owned(), Variant::Int32(8)),
|
||||
("Baz".to_owned(), Variant::Int32(10)),
|
||||
("Unchanged".to_owned(), Variant::Int32(-5)),
|
||||
]
|
||||
.into();
|
||||
let expected_properties = UstrMap::from_iter([
|
||||
(ustr("Foo"), Variant::Int32(8)),
|
||||
(ustr("Baz"), Variant::Int32(10)),
|
||||
(ustr("Unchanged"), Variant::Int32(-5)),
|
||||
]);
|
||||
|
||||
let root_instance = tree.get_instance(root_id).unwrap();
|
||||
assert_eq!(root_instance.name(), "Foo");
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
//! Defines the algorithm for computing a roughly-minimal patch set given an
|
||||
//! existing instance tree and an instance snapshot.
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
mem::take,
|
||||
};
|
||||
use std::{collections::HashMap, mem::take};
|
||||
|
||||
use rbx_dom_weak::types::{Ref, Variant};
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant},
|
||||
ustr, HashMapExt as _, UstrMap, UstrSet,
|
||||
};
|
||||
|
||||
use crate::{RojoRef, REF_POINTER_ATTRIBUTE_PREFIX};
|
||||
|
||||
|
|
@ -99,8 +99,8 @@ fn compute_property_patches(
|
|||
patch_set: &mut PatchSet,
|
||||
tree: &RojoTree,
|
||||
) {
|
||||
let mut visited_properties = HashSet::new();
|
||||
let mut changed_properties = HashMap::new();
|
||||
let mut visited_properties = UstrSet::default();
|
||||
let mut changed_properties = UstrMap::new();
|
||||
|
||||
let attribute_ref_properties = compute_ref_properties(snapshot, tree);
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ fn compute_property_patches(
|
|||
let changed_class_name = if snapshot.class_name == instance.class_name() {
|
||||
None
|
||||
} else {
|
||||
Some(take(&mut snapshot.class_name).into_owned())
|
||||
Some(take(&mut snapshot.class_name))
|
||||
};
|
||||
|
||||
let changed_metadata = if &snapshot.metadata == instance.metadata() {
|
||||
|
|
@ -123,7 +123,7 @@ fn compute_property_patches(
|
|||
};
|
||||
|
||||
for (name, snapshot_value) in take(&mut snapshot.properties) {
|
||||
visited_properties.insert(name.clone());
|
||||
visited_properties.insert(name);
|
||||
|
||||
match instance.properties().get(&name) {
|
||||
Some(instance_value) => {
|
||||
|
|
@ -138,11 +138,11 @@ fn compute_property_patches(
|
|||
}
|
||||
|
||||
for name in instance.properties().keys() {
|
||||
if visited_properties.contains(name.as_str()) {
|
||||
if visited_properties.contains(name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
changed_properties.insert(name.clone(), None);
|
||||
changed_properties.insert(*name, None);
|
||||
}
|
||||
|
||||
for (name, ref_value) in attribute_ref_properties {
|
||||
|
|
@ -163,6 +163,34 @@ fn compute_property_patches(
|
|||
}
|
||||
}
|
||||
|
||||
// !!!!!!!!!! UGLY HACK !!!!!!!!!!
|
||||
//
|
||||
// See RojoTree::insert_instance. Adjust that code also if you are touching this.
|
||||
let actual_class = changed_class_name.unwrap_or(instance.class_name());
|
||||
match actual_class.as_str() {
|
||||
"Model" | "Actor" | "Tool" | "HopperBin" | "Flag" | "WorldModel" | "Workspace"
|
||||
| "Status" => {
|
||||
let migration_prop = ustr("NeedsPivotMigration");
|
||||
// We want to just ignore this if it's being removed by a patch.
|
||||
// Normally this would not matter because serving != building but
|
||||
// if we start syncing models using SerializationService
|
||||
// (or GetObjects) it will affect how Studio deserializes things.
|
||||
if !instance.properties().contains_key(&migration_prop) {
|
||||
changed_properties.insert(migration_prop, Some(Variant::Bool(false)));
|
||||
}
|
||||
match changed_properties.get(&migration_prop) {
|
||||
Some(Some(Variant::Bool(_))) => {}
|
||||
Some(None) => {
|
||||
changed_properties.remove(&migration_prop);
|
||||
}
|
||||
_ => {
|
||||
changed_properties.insert(migration_prop, Some(Variant::Bool(false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
if changed_properties.is_empty()
|
||||
&& changed_name.is_none()
|
||||
&& changed_class_name.is_none()
|
||||
|
|
@ -250,9 +278,9 @@ fn compute_children_patches(
|
|||
fn compute_ref_properties(
|
||||
snapshot: &InstanceSnapshot,
|
||||
tree: &RojoTree,
|
||||
) -> HashMap<String, Option<Variant>> {
|
||||
let mut map = HashMap::new();
|
||||
let attributes = match snapshot.properties.get("Attributes") {
|
||||
) -> UstrMap<Option<Variant>> {
|
||||
let mut map = UstrMap::new();
|
||||
let attributes = match snapshot.properties.get(&ustr("Attributes")) {
|
||||
Some(Variant::Attributes(attrs)) => attrs,
|
||||
_ => return map,
|
||||
};
|
||||
|
|
@ -284,9 +312,9 @@ fn compute_ref_properties(
|
|||
}
|
||||
};
|
||||
if let Some(target_id) = tree.get_specified_id(&rojo_ref) {
|
||||
map.insert(prop_name.to_string(), Some(Variant::Ref(target_id)));
|
||||
map.insert(ustr(prop_name), Some(Variant::Ref(target_id)));
|
||||
} else {
|
||||
map.insert(prop_name.to_string(), None);
|
||||
map.insert(ustr(prop_name), None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,11 +342,11 @@ mod test {
|
|||
let snapshot_id = Ref::new();
|
||||
let snapshot = InstanceSnapshot {
|
||||
snapshot_id,
|
||||
properties: [("Self".to_owned(), Variant::Ref(snapshot_id))].into(),
|
||||
properties: UstrMap::from_iter([(ustr("Self"), Variant::Ref(snapshot_id))]),
|
||||
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("foo"),
|
||||
class_name: Cow::Borrowed("foo"),
|
||||
class_name: ustr("foo"),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
||||
|
|
@ -329,7 +357,10 @@ mod test {
|
|||
id: root_id,
|
||||
changed_name: None,
|
||||
changed_class_name: None,
|
||||
changed_properties: [("Self".to_owned(), Some(Variant::Ref(root_id)))].into(),
|
||||
changed_properties: UstrMap::from_iter([(
|
||||
ustr("Self"),
|
||||
Some(Variant::Ref(root_id)),
|
||||
)]),
|
||||
changed_metadata: None,
|
||||
}],
|
||||
added_instances: Vec::new(),
|
||||
|
|
@ -353,19 +384,19 @@ mod test {
|
|||
let snapshot = InstanceSnapshot {
|
||||
snapshot_id,
|
||||
children: vec![InstanceSnapshot {
|
||||
properties: [("Self".to_owned(), Variant::Ref(snapshot_id))].into(),
|
||||
properties: UstrMap::from_iter([(ustr("Self"), Variant::Ref(snapshot_id))]),
|
||||
|
||||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("child"),
|
||||
class_name: Cow::Borrowed("child"),
|
||||
class_name: ustr("child"),
|
||||
children: Vec::new(),
|
||||
}],
|
||||
|
||||
metadata: Default::default(),
|
||||
properties: HashMap::new(),
|
||||
properties: UstrMap::new(),
|
||||
name: Cow::Borrowed("foo"),
|
||||
class_name: Cow::Borrowed("foo"),
|
||||
class_name: ustr("foo"),
|
||||
};
|
||||
|
||||
let patch_set = compute_patch_set(Some(snapshot), &tree, root_id);
|
||||
|
|
@ -376,9 +407,9 @@ mod test {
|
|||
instance: InstanceSnapshot {
|
||||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
properties: [("Self".to_owned(), Variant::Ref(root_id))].into(),
|
||||
properties: UstrMap::from_iter([(ustr("Self"), Variant::Ref(root_id))]),
|
||||
name: Cow::Borrowed("child"),
|
||||
class_name: Cow::Borrowed("child"),
|
||||
class_name: ustr("child"),
|
||||
children: Vec::new(),
|
||||
},
|
||||
}],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use insta::assert_yaml_snapshot;
|
||||
|
||||
use rbx_dom_weak::{ustr, UstrMap};
|
||||
use rojo_insta_ext::RedactionMap;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -18,7 +19,7 @@ fn set_name_and_class_name() {
|
|||
updated_instances: vec![PatchUpdate {
|
||||
id: tree.get_root_id(),
|
||||
changed_name: Some("Hello, world!".to_owned()),
|
||||
changed_class_name: Some("Folder".to_owned()),
|
||||
changed_class_name: Some(ustr("Folder")),
|
||||
changed_properties: Default::default(),
|
||||
changed_metadata: None,
|
||||
}],
|
||||
|
|
@ -46,7 +47,7 @@ fn add_property() {
|
|||
id: tree.get_root_id(),
|
||||
changed_name: None,
|
||||
changed_class_name: None,
|
||||
changed_properties: [("Foo".to_owned(), Some("Value of Foo".into()))].into(),
|
||||
changed_properties: UstrMap::from_iter([(ustr("Foo"), Some("Value of Foo".into()))]),
|
||||
changed_metadata: None,
|
||||
}],
|
||||
..Default::default()
|
||||
|
|
@ -74,7 +75,7 @@ fn remove_property() {
|
|||
|
||||
root_instance
|
||||
.properties_mut()
|
||||
.insert("Foo".to_owned(), "Should be removed".into());
|
||||
.insert(ustr("Foo"), "Should be removed".into());
|
||||
}
|
||||
|
||||
let tree_view = view_tree(&tree, &mut redactions);
|
||||
|
|
@ -85,7 +86,7 @@ fn remove_property() {
|
|||
id: tree.get_root_id(),
|
||||
changed_name: None,
|
||||
changed_class_name: None,
|
||||
changed_properties: [("Foo".to_owned(), None)].into(),
|
||||
changed_properties: UstrMap::from_iter([(ustr("Foo"), None)]),
|
||||
changed_metadata: None,
|
||||
}],
|
||||
..Default::default()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
|
||||
use insta::assert_yaml_snapshot;
|
||||
|
||||
use rbx_dom_weak::types::Ref;
|
||||
use rbx_dom_weak::{types::Ref, ustr, UstrMap};
|
||||
use rojo_insta_ext::RedactionMap;
|
||||
|
||||
use crate::snapshot::{compute_patch_set, InstanceSnapshot, RojoTree};
|
||||
|
|
@ -18,7 +18,7 @@ fn set_name_and_class_name() {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("Some Folder"),
|
||||
class_name: Cow::Borrowed("Folder"),
|
||||
class_name: ustr("Folder"),
|
||||
properties: Default::default(),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
|
@ -40,8 +40,8 @@ fn set_property() {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("ROOT"),
|
||||
class_name: Cow::Borrowed("ROOT"),
|
||||
properties: [("PropertyName".into(), "Hello, world!".into())].into(),
|
||||
class_name: ustr("ROOT"),
|
||||
properties: UstrMap::from_iter([(ustr("PropertyName"), "Hello, world!".into())]),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
||||
|
|
@ -61,17 +61,16 @@ fn remove_property() {
|
|||
{
|
||||
let root_id = tree.get_root_id();
|
||||
let mut root_instance = tree.get_instance_mut(root_id).unwrap();
|
||||
root_instance.properties_mut().insert(
|
||||
"Foo".to_owned(),
|
||||
"This should be removed by the patch.".into(),
|
||||
);
|
||||
root_instance
|
||||
.properties_mut()
|
||||
.insert(ustr("Foo"), "This should be removed by the patch.".into());
|
||||
}
|
||||
|
||||
let snapshot = InstanceSnapshot {
|
||||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("ROOT"),
|
||||
class_name: Cow::Borrowed("ROOT"),
|
||||
class_name: ustr("ROOT"),
|
||||
properties: Default::default(),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
|
@ -93,13 +92,13 @@ fn add_child() {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("ROOT"),
|
||||
class_name: Cow::Borrowed("ROOT"),
|
||||
class_name: ustr("ROOT"),
|
||||
properties: Default::default(),
|
||||
children: vec![InstanceSnapshot {
|
||||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("New"),
|
||||
class_name: Cow::Borrowed("Folder"),
|
||||
class_name: ustr("Folder"),
|
||||
properties: Default::default(),
|
||||
children: Vec::new(),
|
||||
}],
|
||||
|
|
@ -132,7 +131,7 @@ fn remove_child() {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Borrowed("ROOT"),
|
||||
class_name: Cow::Borrowed("ROOT"),
|
||||
class_name: ustr("ROOT"),
|
||||
properties: Default::default(),
|
||||
children: Vec::new(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant},
|
||||
Instance, InstanceBuilder, WeakDom,
|
||||
ustr, Instance, InstanceBuilder, Ustr, UstrMap, WeakDom,
|
||||
};
|
||||
|
||||
use crate::{multimap::MultiMap, RojoRef};
|
||||
|
|
@ -94,9 +94,33 @@ impl RojoTree {
|
|||
}
|
||||
|
||||
pub fn insert_instance(&mut self, parent_ref: Ref, snapshot: InstanceSnapshot) -> Ref {
|
||||
// !!!!!!!!!! UGLY HACK !!!!!!!!!!
|
||||
// ! If you are going to change this, go change it in patch_compute/compute_property_patches too
|
||||
//
|
||||
// This is a set of special cases working around a more general problem upstream
|
||||
// in rbx-dom that causes pivots to not build to file correctly, described in
|
||||
// github.com/rojo-rbx/rojo/issues/628 and github.com/rojo-rbx/rbx-dom/issues/385
|
||||
//
|
||||
// We need to insert the NeedsPivotMigration property with a value of false on
|
||||
// every instance that inherits from Model for pivots to build correctly.
|
||||
let hack_needs_pivot_migration = match snapshot.class_name.as_ref() {
|
||||
// This is not a future proof way to do this but the last time a
|
||||
// descendant of Model was added was in 2020 so it's probably fine.
|
||||
"Model" | "Actor" | "Tool" | "HopperBin" | "Flag" | "WorldModel" | "Workspace"
|
||||
| "Status"
|
||||
if !snapshot
|
||||
.properties
|
||||
.contains_key(&ustr("NeedsPivotMigration")) =>
|
||||
{
|
||||
vec![("NeedsPivotMigration", Variant::Bool(false))]
|
||||
}
|
||||
_ => Vec::new(),
|
||||
};
|
||||
|
||||
let builder = InstanceBuilder::empty()
|
||||
.with_class(snapshot.class_name.into_owned())
|
||||
.with_class(snapshot.class_name)
|
||||
.with_name(snapshot.name.into_owned())
|
||||
.with_properties(hack_needs_pivot_migration)
|
||||
.with_properties(snapshot.properties);
|
||||
|
||||
let referent = self.inner.insert(parent_ref, builder);
|
||||
|
|
@ -283,11 +307,11 @@ impl<'a> InstanceWithMeta<'a> {
|
|||
&self.instance.name
|
||||
}
|
||||
|
||||
pub fn class_name(&self) -> &'a str {
|
||||
&self.instance.class
|
||||
pub fn class_name(&self) -> Ustr {
|
||||
self.instance.class
|
||||
}
|
||||
|
||||
pub fn properties(&self) -> &'a HashMap<String, Variant> {
|
||||
pub fn properties(&self) -> &'a UstrMap<Variant> {
|
||||
&self.instance.properties
|
||||
}
|
||||
|
||||
|
|
@ -328,15 +352,15 @@ impl InstanceWithMetaMut<'_> {
|
|||
&self.instance.class
|
||||
}
|
||||
|
||||
pub fn class_name_mut(&mut self) -> &mut String {
|
||||
&mut self.instance.class
|
||||
pub fn set_class_name<'a, S: Into<&'a str>>(&mut self, new_class: S) {
|
||||
self.instance.class = ustr(new_class.into());
|
||||
}
|
||||
|
||||
pub fn properties(&self) -> &HashMap<String, Variant> {
|
||||
pub fn properties(&self) -> &UstrMap<Variant> {
|
||||
&self.instance.properties
|
||||
}
|
||||
|
||||
pub fn properties_mut(&mut self) -> &mut HashMap<String, Variant> {
|
||||
pub fn properties_mut(&mut self) -> &mut UstrMap<Variant> {
|
||||
&mut self.instance.properties
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::{collections::BTreeMap, path::Path};
|
|||
|
||||
use anyhow::Context;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::ustr;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
|
|
@ -30,7 +31,7 @@ pub fn snapshot_csv(
|
|||
let mut snapshot = InstanceSnapshot::new()
|
||||
.name(name)
|
||||
.class_name("LocalizationTable")
|
||||
.properties([("Contents".to_owned(), table_contents.into())])
|
||||
.property(ustr("Contents"), table_contents)
|
||||
.metadata(
|
||||
InstanceMetadata::new()
|
||||
.instigating_source(path)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::path::Path;
|
|||
|
||||
use anyhow::Context;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::ustr;
|
||||
|
||||
use crate::{
|
||||
lua_ast::{Expression, Statement},
|
||||
|
|
@ -23,14 +24,12 @@ pub fn snapshot_json(
|
|||
|
||||
let as_lua = json_to_lua(value).to_string();
|
||||
|
||||
let properties = [("Source".to_owned(), as_lua.into())];
|
||||
|
||||
let meta_path = path.with_file_name(format!("{}.meta.json", name));
|
||||
|
||||
let mut snapshot = InstanceSnapshot::new()
|
||||
.name(name)
|
||||
.class_name("ModuleScript")
|
||||
.properties(properties)
|
||||
.property(ustr("Source"), as_lua)
|
||||
.metadata(
|
||||
InstanceMetadata::new()
|
||||
.instigating_source(path)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ use std::{borrow::Cow, collections::HashMap, path::Path, str};
|
|||
|
||||
use anyhow::Context;
|
||||
use memofs::Vfs;
|
||||
use rbx_dom_weak::types::{Attributes, Ref};
|
||||
use rbx_dom_weak::{
|
||||
types::{Attributes, Ref},
|
||||
HashMapExt as _, Ustr, UstrMap,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -68,7 +71,7 @@ struct JsonModel {
|
|||
name: Option<String>,
|
||||
|
||||
#[serde(alias = "ClassName")]
|
||||
class_name: String,
|
||||
class_name: Ustr,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
id: Option<String>,
|
||||
|
|
@ -82,10 +85,10 @@ struct JsonModel {
|
|||
|
||||
#[serde(
|
||||
alias = "Properties",
|
||||
default = "HashMap::new",
|
||||
default = "UstrMap::new",
|
||||
skip_serializing_if = "HashMap::is_empty"
|
||||
)]
|
||||
properties: HashMap<String, UnresolvedValue>,
|
||||
properties: UstrMap<UnresolvedValue>,
|
||||
|
||||
#[serde(default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
|
||||
attributes: HashMap<String, UnresolvedValue>,
|
||||
|
|
@ -93,7 +96,7 @@ struct JsonModel {
|
|||
|
||||
impl JsonModel {
|
||||
fn into_snapshot(self) -> anyhow::Result<InstanceSnapshot> {
|
||||
let name = self.name.unwrap_or_else(|| self.class_name.clone());
|
||||
let name = self.name.unwrap_or_else(|| self.class_name.to_owned());
|
||||
let class_name = self.class_name;
|
||||
|
||||
let mut children = Vec::with_capacity(self.children.len());
|
||||
|
|
@ -101,7 +104,7 @@ impl JsonModel {
|
|||
children.push(child.into_snapshot()?);
|
||||
}
|
||||
|
||||
let mut properties = HashMap::with_capacity(self.properties.len());
|
||||
let mut properties = UstrMap::with_capacity(self.properties.len());
|
||||
for (key, unresolved) in self.properties {
|
||||
let value = unresolved.resolve(&class_name, &key)?;
|
||||
properties.insert(key, value);
|
||||
|
|
@ -122,7 +125,7 @@ impl JsonModel {
|
|||
snapshot_id: Ref::none(),
|
||||
metadata: Default::default(),
|
||||
name: Cow::Owned(name),
|
||||
class_name: Cow::Owned(class_name),
|
||||
class_name,
|
||||
properties,
|
||||
children,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashMap, path::Path, str};
|
||||
use std::{path::Path, str};
|
||||
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::types::Enum;
|
||||
use rbx_dom_weak::{types::Enum, ustr, HashMapExt as _, UstrMap};
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
|
||||
|
|
@ -15,6 +15,11 @@ pub enum ScriptType {
|
|||
Server,
|
||||
Client,
|
||||
Module,
|
||||
Plugin,
|
||||
LegacyServer,
|
||||
LegacyClient,
|
||||
RunContextServer,
|
||||
RunContextClient,
|
||||
}
|
||||
|
||||
/// Core routine for turning Lua files into snapshots.
|
||||
|
|
@ -31,23 +36,38 @@ pub fn snapshot_lua(
|
|||
.expect("Unable to get RunContext enums!")
|
||||
.items;
|
||||
|
||||
let (class_name, run_context) = match (context.emit_legacy_scripts, script_type) {
|
||||
(false, ScriptType::Server) => ("Script", run_context_enums.get("Server")),
|
||||
(false, ScriptType::Client) => ("Script", run_context_enums.get("Client")),
|
||||
(true, ScriptType::Server) => ("Script", run_context_enums.get("Legacy")),
|
||||
(true, ScriptType::Client) => ("LocalScript", None),
|
||||
(_, ScriptType::Module) => ("ModuleScript", None),
|
||||
let (class_name, run_context) = match script_type {
|
||||
ScriptType::Server => {
|
||||
if context.emit_legacy_scripts {
|
||||
("Script", run_context_enums.get("Legacy"))
|
||||
} else {
|
||||
("Script", run_context_enums.get("Server"))
|
||||
}
|
||||
}
|
||||
ScriptType::Client => {
|
||||
if context.emit_legacy_scripts {
|
||||
("LocalScript", None)
|
||||
} else {
|
||||
("Script", run_context_enums.get("Client"))
|
||||
}
|
||||
}
|
||||
ScriptType::Module => ("ModuleScript", None),
|
||||
ScriptType::Plugin => ("Script", run_context_enums.get("Plugin")),
|
||||
ScriptType::LegacyServer => ("Script", run_context_enums.get("Legacy")),
|
||||
ScriptType::LegacyClient => ("LocalScript", None),
|
||||
ScriptType::RunContextServer => ("Script", run_context_enums.get("Server")),
|
||||
ScriptType::RunContextClient => ("Script", run_context_enums.get("Client")),
|
||||
};
|
||||
|
||||
let contents = vfs.read_to_string_lf_normalized(path)?;
|
||||
let contents_str = contents.as_str();
|
||||
|
||||
let mut properties = HashMap::with_capacity(2);
|
||||
properties.insert("Source".to_owned(), contents_str.into());
|
||||
let mut properties = UstrMap::with_capacity(2);
|
||||
properties.insert(ustr("Source"), contents_str.into());
|
||||
|
||||
if let Some(run_context) = run_context {
|
||||
properties.insert(
|
||||
"RunContext".to_owned(),
|
||||
ustr("RunContext"),
|
||||
Enum::from_u32(run_context.to_owned()).into(),
|
||||
);
|
||||
}
|
||||
|
|
@ -164,6 +184,29 @@ mod test {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_module_from_vfs() {
|
||||
let mut imfs = InMemoryFs::new();
|
||||
imfs.load_snapshot("/foo.plugin.lua", VfsSnapshot::file("Hello there!"))
|
||||
.unwrap();
|
||||
|
||||
let vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot = snapshot_lua(
|
||||
&InstanceContext::with_emit_legacy_scripts(Some(false)),
|
||||
&vfs,
|
||||
Path::new("/foo.plugin.lua"),
|
||||
"foo",
|
||||
ScriptType::Plugin,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
insta::with_settings!({ sort_maps => true }, {
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_server_from_vfs() {
|
||||
let mut imfs = InMemoryFs::new();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{borrow::Cow, collections::HashMap, path::PathBuf};
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use anyhow::{format_err, Context};
|
||||
use rbx_dom_weak::types::Attributes;
|
||||
use rbx_dom_weak::{types::Attributes, Ustr, UstrMap};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{resolution::UnresolvedValue, snapshot::InstanceSnapshot, RojoRef};
|
||||
|
|
@ -23,7 +23,7 @@ pub struct AdjacentMetadata {
|
|||
pub ignore_unknown_instances: Option<bool>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub properties: HashMap<String, UnresolvedValue>,
|
||||
pub properties: UstrMap<UnresolvedValue>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub attributes: HashMap<String, UnresolvedValue>,
|
||||
|
|
@ -117,13 +117,13 @@ pub struct DirectoryMetadata {
|
|||
pub ignore_unknown_instances: Option<bool>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub properties: HashMap<String, UnresolvedValue>,
|
||||
pub properties: UstrMap<UnresolvedValue>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub attributes: HashMap<String, UnresolvedValue>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub class_name: Option<String>,
|
||||
pub class_name: Option<Ustr>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub path: PathBuf,
|
||||
|
|
@ -161,7 +161,7 @@ impl DirectoryMetadata {
|
|||
));
|
||||
}
|
||||
|
||||
snapshot.class_name = Cow::Owned(class_name);
|
||||
snapshot.class_name = class_name;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -202,6 +202,11 @@ pub enum Middleware {
|
|||
ServerScript,
|
||||
ClientScript,
|
||||
ModuleScript,
|
||||
PluginScript,
|
||||
LegacyClientScript,
|
||||
LegacyServerScript,
|
||||
RunContextServerScript,
|
||||
RunContextClientScript,
|
||||
Project,
|
||||
Rbxm,
|
||||
Rbxmx,
|
||||
|
|
@ -227,6 +232,19 @@ impl Middleware {
|
|||
Self::ServerScript => snapshot_lua(context, vfs, path, name, ScriptType::Server),
|
||||
Self::ClientScript => snapshot_lua(context, vfs, path, name, ScriptType::Client),
|
||||
Self::ModuleScript => snapshot_lua(context, vfs, path, name, ScriptType::Module),
|
||||
Self::PluginScript => snapshot_lua(context, vfs, path, name, ScriptType::Plugin),
|
||||
Self::LegacyClientScript => {
|
||||
snapshot_lua(context, vfs, path, name, ScriptType::LegacyClient)
|
||||
}
|
||||
Self::LegacyServerScript => {
|
||||
snapshot_lua(context, vfs, path, name, ScriptType::LegacyServer)
|
||||
}
|
||||
Self::RunContextClientScript => {
|
||||
snapshot_lua(context, vfs, path, name, ScriptType::RunContextClient)
|
||||
}
|
||||
Self::RunContextServerScript => {
|
||||
snapshot_lua(context, vfs, path, name, ScriptType::RunContextServer)
|
||||
}
|
||||
Self::Project => snapshot_project(context, vfs, path, name),
|
||||
Self::Rbxm => snapshot_rbxm(context, vfs, path, name),
|
||||
Self::Rbxmx => snapshot_rbxmx(context, vfs, path, name),
|
||||
|
|
@ -286,6 +304,8 @@ pub fn default_sync_rules() -> &'static [SyncRule] {
|
|||
sync_rule!("*.server.luau", ServerScript, ".server.luau"),
|
||||
sync_rule!("*.client.lua", ClientScript, ".client.lua"),
|
||||
sync_rule!("*.client.luau", ClientScript, ".client.luau"),
|
||||
sync_rule!("*.plugin.lua", PluginScript, ".plugin.lua"),
|
||||
sync_rule!("*.plugin.luau", PluginScript, ".plugin.luau"),
|
||||
sync_rule!("*.{lua,luau}", ModuleScript),
|
||||
sync_rule!("*.project.json", Project, ".project.json"),
|
||||
sync_rule!("*.model.json", JsonModel, ".model.json"),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||
use std::{borrow::Cow, path::Path};
|
||||
|
||||
use anyhow::{bail, Context};
|
||||
use memofs::Vfs;
|
||||
use rbx_dom_weak::types::{Attributes, Ref};
|
||||
use rbx_dom_weak::{
|
||||
types::{Attributes, Ref},
|
||||
ustr, HashMapExt as _, Ustr, UstrMap,
|
||||
};
|
||||
use rbx_reflection::ClassTag;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -88,14 +91,10 @@ pub fn snapshot_project_node(
|
|||
) -> anyhow::Result<Option<InstanceSnapshot>> {
|
||||
let project_folder = project_path.parent().unwrap();
|
||||
|
||||
let class_name_from_project = node
|
||||
.class_name
|
||||
.as_ref()
|
||||
.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 = UstrMap::new();
|
||||
let mut children = Vec::new();
|
||||
let mut metadata = InstanceMetadata::new().context(context);
|
||||
|
||||
|
|
@ -136,7 +135,7 @@ pub fn snapshot_project_node(
|
|||
let class_name_from_inference = infer_class_name(&name, parent_class);
|
||||
|
||||
let class_name = match (
|
||||
class_name_from_project,
|
||||
node.class_name,
|
||||
class_name_from_path,
|
||||
class_name_from_inference,
|
||||
&node.path,
|
||||
|
|
@ -249,7 +248,7 @@ pub fn snapshot_project_node(
|
|||
_ => {}
|
||||
}
|
||||
|
||||
properties.insert(key.clone(), value);
|
||||
properties.insert(*key, value);
|
||||
}
|
||||
|
||||
if !node.attributes.is_empty() {
|
||||
|
|
@ -304,7 +303,7 @@ pub fn snapshot_project_node(
|
|||
}))
|
||||
}
|
||||
|
||||
fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Cow<'static, str>> {
|
||||
fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Ustr> {
|
||||
// If className wasn't defined from another source, we may be able
|
||||
// to infer one.
|
||||
|
||||
|
|
@ -317,18 +316,18 @@ fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Cow<'stati
|
|||
let descriptor = rbx_reflection_database::get().classes.get(name)?;
|
||||
|
||||
if descriptor.tags.contains(&ClassTag::Service) {
|
||||
return Some(Cow::Owned(name.to_owned()));
|
||||
return Some(ustr(name));
|
||||
}
|
||||
} 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()));
|
||||
return Some(ustr(name));
|
||||
}
|
||||
} else if parent_class == "Workspace" {
|
||||
// Workspace has a special Terrain class inside it
|
||||
if name == "Terrain" {
|
||||
return Some(Cow::Owned(name.to_owned()));
|
||||
return Some(ustr(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
source: src/snapshot_middleware/lua.rs
|
||||
expression: instance_snapshot
|
||||
---
|
||||
snapshot_id: "00000000000000000000000000000000"
|
||||
metadata:
|
||||
ignore_unknown_instances: false
|
||||
instigating_source:
|
||||
Path: /foo.plugin.lua
|
||||
relevant_paths:
|
||||
- /foo.plugin.lua
|
||||
- /foo.meta.json
|
||||
context:
|
||||
emit_legacy_scripts: false
|
||||
specified_id: ~
|
||||
name: foo
|
||||
class_name: Script
|
||||
properties:
|
||||
RunContext:
|
||||
Enum: 3
|
||||
Source:
|
||||
String: Hello there!
|
||||
children: []
|
||||
|
|
@ -2,6 +2,7 @@ use std::path::Path;
|
|||
|
||||
use anyhow::Context;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::ustr;
|
||||
|
||||
use crate::{
|
||||
lua_ast::{Expression, Statement},
|
||||
|
|
@ -23,14 +24,12 @@ pub fn snapshot_toml(
|
|||
|
||||
let as_lua = toml_to_lua(value).to_string();
|
||||
|
||||
let properties = [("Source".to_owned(), as_lua.into())];
|
||||
|
||||
let meta_path = path.with_file_name(format!("{}.meta.json", name));
|
||||
|
||||
let mut snapshot = InstanceSnapshot::new()
|
||||
.name(name)
|
||||
.class_name("ModuleScript")
|
||||
.properties(properties)
|
||||
.property(ustr("Source"), as_lua)
|
||||
.metadata(
|
||||
InstanceMetadata::new()
|
||||
.instigating_source(path)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{path::Path, str};
|
||||
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::ustr;
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
|
||||
|
|
@ -15,14 +16,12 @@ pub fn snapshot_txt(
|
|||
let contents = vfs.read_to_string(path)?;
|
||||
let contents_str = contents.as_str();
|
||||
|
||||
let properties = [("Value".to_owned(), contents_str.into())];
|
||||
|
||||
let meta_path = path.with_file_name(format!("{}.meta.json", name));
|
||||
|
||||
let mut snapshot = InstanceSnapshot::new()
|
||||
.name(name)
|
||||
.class_name("StringValue")
|
||||
.properties(properties)
|
||||
.property(ustr("Value"), contents_str)
|
||||
.metadata(
|
||||
InstanceMetadata::new()
|
||||
.instigating_source(path)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
//! Utiilty that helps redact nondeterministic information from trees so that
|
||||
//! they can be part of snapshot tests.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rbx_dom_weak::types::{Ref, Variant};
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant},
|
||||
Ustr, UstrMap,
|
||||
};
|
||||
use rojo_insta_ext::RedactionMap;
|
||||
use serde::Serialize;
|
||||
|
||||
|
|
@ -34,8 +35,8 @@ pub fn intern_tree(tree: &RojoTree, redactions: &mut RedactionMap) {
|
|||
struct InstanceView {
|
||||
id: Ref,
|
||||
name: String,
|
||||
class_name: String,
|
||||
properties: HashMap<String, Variant>,
|
||||
class_name: Ustr,
|
||||
properties: UstrMap<Variant>,
|
||||
metadata: InstanceMetadata,
|
||||
children: Vec<InstanceView>,
|
||||
}
|
||||
|
|
@ -46,7 +47,7 @@ fn extract_instance_view(tree: &RojoTree, id: Ref) -> InstanceView {
|
|||
InstanceView {
|
||||
id: instance.id(),
|
||||
name: instance.name().to_owned(),
|
||||
class_name: instance.class_name().to_owned(),
|
||||
class_name: instance.class_name(),
|
||||
properties: instance.properties().clone(),
|
||||
metadata: instance.metadata().clone(),
|
||||
children: instance
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ impl ApiService {
|
|||
session_id: self.serve_session.session_id(),
|
||||
project_name: self.serve_session.project_name().to_owned(),
|
||||
expected_place_ids: self.serve_session.serve_place_ids().cloned(),
|
||||
unexpected_place_ids: self.serve_session.blocked_place_ids().cloned(),
|
||||
place_id: self.serve_session.place_id(),
|
||||
game_id: self.serve_session.game_id(),
|
||||
root_instance_id,
|
||||
|
|
@ -280,7 +281,7 @@ impl ApiService {
|
|||
/// If this instance is represented by a script, try to find the correct .lua or .luau
|
||||
/// file to open to edit it.
|
||||
fn pick_script_path(instance: InstanceWithMeta<'_>) -> Option<PathBuf> {
|
||||
match instance.class_name() {
|
||||
match instance.class_name().as_str() {
|
||||
"Script" | "LocalScript" | "ModuleScript" => {}
|
||||
_ => return None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use std::{
|
|||
collections::{HashMap, HashSet},
|
||||
};
|
||||
|
||||
use rbx_dom_weak::types::{Ref, Variant, VariantType};
|
||||
use rbx_dom_weak::{
|
||||
types::{Ref, Variant, VariantType},
|
||||
Ustr, UstrMap,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -84,12 +87,12 @@ impl<'a> SubscribeMessage<'a> {
|
|||
pub struct InstanceUpdate {
|
||||
pub id: Ref,
|
||||
pub changed_name: Option<String>,
|
||||
pub changed_class_name: Option<String>,
|
||||
pub changed_class_name: Option<Ustr>,
|
||||
|
||||
// TODO: Transform from HashMap<String, Option<_>> to something else, since
|
||||
// TODO: Transform from UstrMap<String, Option<_>> to something else, since
|
||||
// null will get lost when decoding from JSON in some languages.
|
||||
#[serde(default)]
|
||||
pub changed_properties: HashMap<String, Option<Variant>>,
|
||||
pub changed_properties: UstrMap<Option<Variant>>,
|
||||
pub changed_metadata: Option<InstanceMetadata>,
|
||||
}
|
||||
|
||||
|
|
@ -113,8 +116,8 @@ pub struct Instance<'a> {
|
|||
pub id: Ref,
|
||||
pub parent: Ref,
|
||||
pub name: Cow<'a, str>,
|
||||
pub class_name: Cow<'a, str>,
|
||||
pub properties: HashMap<String, Cow<'a, Variant>>,
|
||||
pub class_name: Ustr,
|
||||
pub properties: UstrMap<Cow<'a, Variant>>,
|
||||
pub children: Cow<'a, [Ref]>,
|
||||
pub metadata: Option<InstanceMetadata>,
|
||||
}
|
||||
|
|
@ -125,14 +128,14 @@ impl Instance<'_> {
|
|||
.properties()
|
||||
.iter()
|
||||
.filter(|(_key, value)| property_filter(Some(value)))
|
||||
.map(|(key, value)| (key.clone(), Cow::Borrowed(value)))
|
||||
.map(|(key, value)| (*key, Cow::Borrowed(value)))
|
||||
.collect();
|
||||
|
||||
Instance {
|
||||
id: source.id(),
|
||||
parent: source.parent(),
|
||||
name: Cow::Borrowed(source.name()),
|
||||
class_name: Cow::Borrowed(source.class_name()),
|
||||
class_name: source.class_name(),
|
||||
properties,
|
||||
children: Cow::Borrowed(source.children()),
|
||||
metadata: Some(InstanceMetadata::from_rojo_metadata(source.metadata())),
|
||||
|
|
@ -157,6 +160,7 @@ pub struct ServerInfoResponse {
|
|||
pub protocol_version: u64,
|
||||
pub project_name: String,
|
||||
pub expected_place_ids: Option<HashSet<u64>>,
|
||||
pub unexpected_place_ids: Option<HashSet<u64>>,
|
||||
pub game_id: Option<u64>,
|
||||
pub place_id: Option<u64>,
|
||||
pub root_instance_id: Ref,
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ impl UiService {
|
|||
.map(|(key, value)| {
|
||||
html! {
|
||||
<div class="instance-property" title={ Self::display_value(value) }>
|
||||
{ key.clone() } ": " { format!("{:?}", value.ty()) }
|
||||
{ key.as_str() } ": " { format!("{:?}", value.ty()) }
|
||||
</div>
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -502,12 +502,35 @@ fn ref_properties_patch_update() {
|
|||
read_response.intern_and_redact(&mut redactions, root_id)
|
||||
);
|
||||
|
||||
let project_path = session.path().join("default.project.json");
|
||||
let mut project_content = fs::read(&project_path).unwrap();
|
||||
// Adding a newline to force the change processor to pick up a change.
|
||||
project_content.push(b'\n');
|
||||
let target_path = session.path().join("ModelTarget.model.json");
|
||||
|
||||
fs::write(project_path, project_content).unwrap();
|
||||
// Inserting scale just to force the change processor to run
|
||||
fs::write(
|
||||
target_path,
|
||||
r#"{
|
||||
"id": "model target",
|
||||
"className": "Folder",
|
||||
"children": [
|
||||
{
|
||||
"name": "ModelPointer",
|
||||
"className": "Model",
|
||||
"attributes": {
|
||||
"Rojo_Target_PrimaryPart": "model target"
|
||||
},
|
||||
"properties": {
|
||||
"Scale": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let subscribe_response = session.get_api_subscribe(0).unwrap();
|
||||
assert_yaml_snapshot!(
|
||||
"ref_properties_patch_update_subscribe",
|
||||
subscribe_response.intern_and_redact(&mut redactions, ())
|
||||
);
|
||||
|
||||
let read_response = session.get_api_read(root_id).unwrap();
|
||||
assert_yaml_snapshot!(
|
||||
|
|
@ -516,3 +539,55 @@ fn ref_properties_patch_update() {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_pivot_migration() {
|
||||
run_serve_test("pivot_migration", |session, mut redactions| {
|
||||
let info = session.get_api_rojo().unwrap();
|
||||
let root_id = info.root_instance_id;
|
||||
|
||||
assert_yaml_snapshot!("pivot_migration_info", redactions.redacted_yaml(info));
|
||||
|
||||
let read_response = session.get_api_read(root_id).unwrap();
|
||||
assert_yaml_snapshot!(
|
||||
"pivot_migration_all",
|
||||
read_response.intern_and_redact(&mut redactions, root_id)
|
||||
);
|
||||
|
||||
let project_path = session.path().join("default.project.json");
|
||||
|
||||
fs::write(
|
||||
project_path,
|
||||
r#"{
|
||||
"name": "pivot_migration",
|
||||
"tree": {
|
||||
"$className": "DataModel",
|
||||
"Workspace": {
|
||||
"Model": {
|
||||
"$className": "Model"
|
||||
},
|
||||
"Tool": {
|
||||
"$path": "Tool.model.json"
|
||||
},
|
||||
"Actor": {
|
||||
"$className": "Actor"
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let subscribe_response = session.get_api_subscribe(0).unwrap();
|
||||
assert_yaml_snapshot!(
|
||||
"model_pivot_migration_all",
|
||||
subscribe_response.intern_and_redact(&mut redactions, ())
|
||||
);
|
||||
|
||||
let read_response = session.get_api_read(root_id).unwrap();
|
||||
assert_yaml_snapshot!(
|
||||
"model_pivot_migration_all-2",
|
||||
read_response.intern_and_redact(&mut redactions, root_id)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue