Commit graph

1536 commits

Author SHA1 Message Date
astrid
9aae24a9ad
Merge a6e9939d6c into 15939b1647 2026-06-04 16:06:13 +02:00
EgoMoose
15939b1647
Add ignorable glob support (#1256) 2026-06-02 20:40:12 -07:00
AK-Khan02
0afb26e143
Update stale README and contributor documentation (#1269) 2026-06-02 09:11:41 -07:00
boatbomber
1abf675949
Graceful errors instead of crashing (#1267) 2026-06-01 20:02:39 -07:00
boatbomber
85655ca84f
Heuristic hydration matching instead of hard dependency on GetChildren ordering (#1266)
### Summary

When two or more sibling instances share the same `Name` and
`ClassName`, Rojo's reconciler previously paired them with their
server-side counterparts purely by child order (first-unvisited match in
`GetChildren()` order). If the workspace child order ever diverged from
the server's, the wrong instance got paired so each duplicate could
inherit a sibling's properties.

This is the root of the #1257 bug: the welded parts would oscillate
between positions on each connect/disconnect because hydration kept
mis-pairing them. (#1265 stopped the sync fallback from scrambling child
order in the first place but this PR makes hydration robust even when
order *does* diverge.)

This PR makes `hydrate` break ties by comparing properties: when several
existing children match on `Name`+`ClassName`, it scores each candidate
by how many of the virtual instance's properties match the candidate's
live values, and picks the best. Order remains the tiebreak when scores
are equal, so behavior is unchanged for uniquely-named instances and for
indistinguishable siblings.

### Changes

- `trueEquals.lua`: extracted verbatim from `diff.lua` (the fuzzy
value-equality helper) so it can be shared. No behavior change;
`diff.lua` now requires it.
- `countMatchingProperties.lua`: added
`countMatchingProperties(instance, virtualInstance, instanceMap) ->
number`. Skips `Ref` properties (the instanceMap isn't fully built
mid-hydrate, so refs can't be decoded reliably, and they're a poor
disambiguator anyway) and any property that can't be read or decoded.
- `hydrate.lua`: See details below.

### Hydrate Changes

This touches `hydrate`, which runs over the whole tree on every
connect/resync, so I want state clearly that **the common path is faster
than before, not slower** even for parents with thousands of children!

The old algorithm was a nested scan: for each of `V` virtual children,
scan existing children until the first unvisited `Name`+`ClassName`
match. Two costs stand out:
- A `pcall` (to guard DataModel permission errors) ran on every
comparison (up to `V*E` `pcall`s per parent).
- Even for in-order trees the re-scanning of the visited prefix made it
`O(V^2)`.

The new algorithm does a single bucketing pass, then `O(1)` lookups:
1. One `O(E)` pass groups existing children into nested
`buckets[name][className]` tables. This runs exactly `E` `pcall`s total
(one per child), down from the `V*E` worst case.
2. Each virtual child does an `O(1)` bucket lookup to find its
candidates.
3. A per-bucket cursor skips already-paired children, so order-based
matching is amortized `O(1)` per child instead of rescanning.

| Scenario | Old | New |
| ------------------------------------------------ |
--------------------------------------- |
--------------------------------------------- |
| Unique-named children (typical, incl. thousands) | `O(V^2)`, plus up
to `V*E` pcalls | `O(V + E)`, plus exactly `E` pcalls |
| `C <= 32` candidates | `O(C^2)` | `O(P * C^2)` scoring |
| `C > 32` candidates | `O(C^2)` | `O(C)` |

Property scoring (`getProperty`/`decodeValue`/`trueEquals`) is the only
new expense, and it's gated two ways:
- It runs only when a `Name`+`ClassName` group has >=2 candidates (i.e.
never for uniquely-named instances).
- A cap, `MAX_CANDIDATES_TO_SCORE = 32`, means scoring only kicks in
once a group has <=32 unvisited candidates. A folder of thousands of
identically-named parts therefore does not trigger scoring; it falls
back to the original order-based pairing. The worst-case added scoring
work is bounded to roughly `32^2` property comparisons per group,
independent of group size.

So overall this is faster when you have unique names or many children.
It is slower but more robust when you have small groups of duplicate
names. Memory usage is increased as it creates the candidate buckets.
2026-06-01 17:29:22 -07:00
boatbomber
ae8735c80a
Fix replaceInstances messing up GetChildren ordering (#1265)
Fixes #1257. replaceInstances now preserves GetChildren ordering.

I also had the unit tests unreliably say that Packages wasn't a member
of ReplicatedStorage so I added WaitForChild and tests run 100% for me
now.
2026-06-01 17:04:25 -07:00
Ken Loeffler
988efb45b1
Use lossy conversion for msgpack UInt64 decode in plugin (#1255) 2026-05-29 10:45:08 -07:00
Micah
9bbb1edd79
Upload plugin as part of release workflow (#1227) 2026-02-14 11:10:36 -08:00
Ivan Matthew
a2adf2b517
Improves sourcemap path handling with pathdiff (#1217) 2026-02-12 19:17:28 -08:00
Micah
4deda0e155
Use msgpack for API (#1176) 2026-02-12 18:37:24 -08:00
ari
4df2d3c5f8
Add actor, bindables and remotes to json_model_classes (#1199) 2026-02-12 17:34:32 -08:00
boatbomber
4965165ad5
Add option to forget prior info for place in reminder notif (#1215) 2026-01-23 21:15:34 +00:00
boatbomber
68eab3479a
Fix notification unmount thread cancel bug (#1211) 2026-01-19 16:35:19 -08:00
ari
a6e9939d6c
Merge branch 'master' into name-prop 2026-01-20 01:10:20 +01:00
astrid
5957368c04
Remove redundant code
Can't remember why I added this one
2026-01-20 01:08:59 +01:00
astrid
78916c8a63
Revert 2 semantic changes 2026-01-20 00:59:34 +01:00
astrid
791ccfcfd1
Remove addition of 'Actor' to json_model_classes 2026-01-20 00:55:03 +01:00
astrid
3500ebe02a
Update CHANGELOG.md 2026-01-20 00:54:18 +01:00
Ivan Matthew
2a1102fc55
Implement VFS Path normalization for improved cross-platform tree synchronization (#1201) 2026-01-19 15:04:59 -08:00
Ken Loeffler
02b41133f8
Use post for ref patch and serialize (#1192) 2026-01-19 22:44:42 +00:00
Astrid
0e1364945f
Avoid clone in src/syncback/file_names.rs 2026-01-12 14:41:12 +01:00
ari
3a6aae65f7
Avoid clone in src/syncback/file_names.rs
Co-authored-by: krakow10 <krakow20@gmail.com>
2026-01-12 14:35:46 +01:00
ari
d13d229eef
Avoid clone in src/snapshot_middleware/json_model.rs
Co-authored-by: krakow10 <krakow20@gmail.com>
2026-01-12 14:35:18 +01:00
ari
9a485d88ce
Avoid clone in src/snapshot_middleware/lua.rs
Co-authored-by: krakow10 <krakow20@gmail.com>
2026-01-12 14:35:06 +01:00
astrid
020d72faef
fix: improve middleware selection for actor and other container classes 2025-12-18 05:10:53 +01:00
astrid
60d150f4c6
feat: optimize name handling for leaf scripts with invalid names
Prefer slugified filenames + adjacent meta files for scripts without children instead of forcing directory creation
2025-12-18 04:43:47 +01:00
astrid
73dab330b5
test: remove oudated json_model_legacy_name test 2025-12-15 20:32:28 +01:00
astrid
790312a5b0
fix: lack of .model.json support 2025-12-15 20:26:25 +01:00
astrid
5c396322d9
fix: name prop not properly syncing 2025-12-15 19:08:18 +01:00
astrid
37e44e474a
feat: support name property in meta and model jsons 2025-12-15 18:45:59 +01:00
Micah
d08780fc14
Ensure that pruned Instances aren't treated as existing in syncback (#1179)
Closes #1178.
2025-11-29 21:21:48 -08:00
Micah
b89cc7f398
Release memofs v0.3.1 (#1175) 2025-11-27 12:32:57 -08:00
Micah
42568b9709
Release Rojo v7.7.0-rc.1 (#1174) 2025-11-27 12:10:57 -08:00
boatbomber
87f58e0a55
Use WebSocket instead of Long Polling (#1142) 2025-11-26 19:57:01 -08:00
Micah
a61a1bef55
Roundtrip schemas in syncback (#1173) 2025-11-26 16:11:39 -08:00
Micah
a99e877b7c
Actually skip .gitignore if --skip-git is passed to init (#1172) 2025-11-26 13:59:12 -08:00
Ken Loeffler
93e9c51204
Fix rojo plugin install by adding Vfs::exists (#1169) 2025-11-21 07:04:34 -08:00
Ken Loeffler
015b5bda14
Set crate and plugin versions to 7.7.0-prealpha (#1170) 2025-11-21 07:02:09 -08:00
Micah
2b47861a4f
Properly support EnumItem variants in hashing and variant_eq (#1165) 2025-11-19 19:18:14 -08:00
Micah
9b5a07191b
Implement Syncback to support converting Roblox files to a Rojo project (#937)
This is a very large commit.
Consider checking the linked PR for more information.
2025-11-19 09:21:33 -08:00
boatbomber
071b6e7e23
Improved string diff viewer (#994) 2025-11-18 20:26:44 -08:00
quaywinn
31ec216a95
Remove pairs() and ipairs() (#1150) 2025-11-18 18:49:52 -08:00
Micah
ea70d89291
Support .jsonc extension for all JSON files (#1159) 2025-11-18 18:47:43 -08:00
quaywinn
03410ced6d
Use buffer for ClassIcon EditableImages (#1149) 2025-11-07 13:07:19 -08:00
Micah
825726c883
Release 7.6.1 (#1151) 2025-11-06 18:49:05 -08:00
boatbomber
54e63d88d4
Slightly improve initial sync hangs (#1140) 2025-11-06 00:06:42 -08:00
boatbomber
4018c97cb6
Make CHANGELOG.md use consistent style (#1146) 2025-10-28 19:26:48 -07:00
boatbomber
d0b029f995
Add JSONC Support for Project, Meta, and Model JSON files (#1144)
Replaces `serde_json` parsing with `jsonc-parser` throughout the
codebase, enabling support for **comments** and **trailing commas** in
all JSON files including `.project.json`, `.model.json`, and
`.meta.json` files.
MSRV bumps from `1.83.0` to `1.88.0` in order to
use the jsonc_parser dependency.
2025-10-28 17:29:57 -07:00
Sebastian Stachowicz
aabe6d11b2
Update default gitignores to include sourcemap (#1145) 2025-10-28 17:28:55 -07:00
boatbomber
181cc37744
Improve sync fallback robustness (#1135) 2025-10-20 20:13:47 -07:00