Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update reconciler / reify to use CreateMeshPartAsync to create mesh parts #534

Closed

Conversation

unix-system
Copy link

@unix-system unix-system commented Apr 18, 2022

Closes #402.

Problem

Currently, Rojo does not support creation of some instances and properties via the Studio plugin - notably UnionOperations and MeshParts. MeshParts can in fact be created by Plugins through the InsertService.CreateMeshPartAsync method at Plugin security.

This impacts developers using Rojo to work, as it prevents them from live importing any such instances (and can only be created from a file via rojo build or manual import).

Solution

This pull request exclusively modifies the Lua plugin; no changes were necessary to the Rojo binary itself. The changes have a soft dependency on a pull request to rbx-dom to update the database files, although this is not a requirement.

The primary change was to modify the reify function to include a switch for custom instance creation logic which could be expanded in the future if necessary.

This change was coupled closely with the implementation of the requiresRecreate property of ApiInstanceUpdate objects, which is a partial replacement for the changedClassName property. This property triggers a condition in the applyPatch function to recreate the instance using reify if the requiresRecreate property is present (previously done for the changedClassName property).

The requiresRecreate property is set during the creation of an update patch (either in batch, in encodePatchUpdate, or during diff).

Tests

Tests have been implemented which support the new feature being added. A dedicated test project (test-projects/mesh_parts/default.project.json) has been included with two MeshParts (one rbxm and one rbxmx), of the Utah Teapot.

image

Other

The development version of Rojo was bumped to 7.0.0 (latest).

@unix-system unix-system marked this pull request as ready for review April 18, 2022 23:18
}

for propertyName in pairs(properties) do
if propertyName == "Name" then
update.changedName = instance.Name
else
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change, whilst structural (it now encodes the Name field as well as setting the changedName property) has not changed the intended logic and is more concise.

Copy link
Contributor

@LPGhatguy LPGhatguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks good, thanks for the submission!

Can you back out the change to database.json? We should be able to land any updates to rbx_dom_lua in a separate PR and it is a frequent source of merge conflicts.

I mentioned in the review comments, but I think we should remove requiresRecreate from the patch type and instead calculate it during applyPatch. The Rojo server produces most of the patches that the plugin receives and doesn't have any knowledge of what would require an instance to be recreated. It's bets if we let the plugin decide for itself when it goes to apply a change.

-- Custom logic for MeshParts
-- see: https://github.com/rojo-rbx/rojo/issues/402
if className == "MeshPart" then
local okMeshId, meshId = decodeValue(properties.MeshId, instanceMap)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to handle okMeshId, because the second return value will not be a mesh ID if this failed to decode.

@@ -25,6 +25,7 @@ local ApiInstanceUpdate = t.interface({
id = RbxId,
changedName = t.optional(t.string),
changedClassName = t.optional(t.string),
requiresRecreate = t.optional(t.boolean),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should update this interface at all. The server generates most of the patches that the Rojo plugin handles and it does not populate requiresRecreate. We can calculate this when we go to apply a patch instead.

-- If the instance's className changed, or there is custom recreate logic,
-- we have a bumpy ride ahead while we recreate this instance and move all
-- of its children into the new version atomically...ish.
if update.requiresRecreate then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are comments in this block of code about its caveats, notably not preserving existing properties if we end up needing to recreate an instance. It's probably not the end of the world, but some of the comments I left about this mostly occurring during Folder<->ModuleScript transitions are probably not accurate anymore.

it("should recreate instance in the update when the instance's ClassName changes", function()
local part = Instance.new("Part")
local properties = {
ClassName = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should set this value to a real ClassName so that future validation in the patch update function won't choke when it sees a bool instead.

@@ -156,7 +158,33 @@ return function()
expect(value.Value).to.equal("WORLD")
end)

it("should recreate instances when changedClassName is set, preserving children", function()
it("should recreate instances for MeshId updates", function()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great test!

-- If the instance's className changed, or there is custom recreate logic,
-- we have a bumpy ride ahead while we recreate this instance and move all
-- of its children into the new version atomically...ish.
if update.requiresRecreate then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having requiresRecreate as a property here, we should check the conditions that would cause us to recreate an instance directly. For now, that's just changedClassName ~= nil or changedProperties["MeshId"] ~= nil.


-- It is okay to provide default properties here, because
-- they will be overriden on the update cycle
return InsertService:CreateMeshPartAsync(meshId, Enum.CollisionFidelity.Default, Enum.RenderFidelity.Automatic)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first time we'll be introducing an async function into Rojo's reconciler bits. This is a possible source of bugs that we should watch out for in the future.

Comment on lines +51 to +52
-- It is okay to provide default properties here, because
-- they will be overriden on the update cycle
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- It is okay to provide default properties here, because
-- they will be overriden on the update cycle
-- It is okay to provide default properties here, because
-- they will be set when properties are applied in reify.

@LPGhatguy LPGhatguy added the status: needs review This work is mostly done, but just needs work to integrate and merge it. label Jun 29, 2022
@unix-system unix-system force-pushed the feat/createmeshpartasync branch from 50d350c to 6c1beb9 Compare November 15, 2023 10:39
@unix-system unix-system marked this pull request as draft November 15, 2023 10:47
@GreenAppers
Copy link

Hm. Why was this closed?

@sasial-dev
Copy link
Contributor

It was closed in favour of #786.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs review This work is mostly done, but just needs work to integrate and merge it.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use CreateMeshPartAsync to create mesh parts
4 participants