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

rbx_dom_weak should have a concept of "proxy properties" #277

Open
kennethloeffler opened this issue May 27, 2023 · 4 comments
Open

rbx_dom_weak should have a concept of "proxy properties" #277

kennethloeffler opened this issue May 27, 2023 · 4 comments
Assignees
Labels

Comments

@kennethloeffler
Copy link
Member

kennethloeffler commented May 27, 2023

Proxy properties are those properties that are mutually dependent, for example (I'll only be listing read and/or write scriptable properties here, in order of how important I think they are):

  • BasePart.Position, BasePart.Orientation, BasePart.Rotation, and BasePart.CFrame
  • Attachment.CFrame, Attachment.Orientation, Attachment.Position, Attachment.Rotation, Attachment.WorldCFrame etc.
  • Lighting.TimeOfDay and Lighting.ClockTime
  • Model.WorldPivot , Model.PrimaryPart, and BasePart.PivotOffset
  • BasePart.BrickColor and BasePart.Color
  • BaseScript.Enabled and BaseScript.Disabled
  • ScreenGui.IgnoreGuiInset and ScreenGui.ScreenInsets
  • Others?

In Roblox's DOM, proxy properties are populated and reflect changes to one another out of the box. It's a questionable amount of work to catalogue and maintain the consistency of proxy properties in a runtime like Lune, and right now, consumers are totally responsible for both.

At the same time, this will mean more maintenance burden on us. It would be great to find some data we could use to automate some of this (in my cursory search of Max's client tracker I was unable to find any), but failing that we could target only the most important proxy properties.

@Dekkonot
Copy link
Member

Dekkonot commented Jul 7, 2023

Given that we currently expose Instance.properties as a public struct member, it isn't possible to keep track of this 100%. However, I think if we added something akin to Instance.set_property and Instance.get_property it wouldn't be unreasonable to have 'proxies' that could intercept what a property was being read or written as.

However, I think that might be beyond rbx_dom_weak. It is, by its nature weakly typed so it knowing about properties like this feels weird. Between things like UniqueId and this, it may be time to start seriously considering what an implementation of rbx_dom_strong would look like.

@kennethloeffler
Copy link
Member Author

kennethloeffler commented Jul 12, 2023

rbx_dom_strong

I'm still not convinced that this would be useful, but this is a conversation for another issue

So anyway ... I think we can at least automate cataloguing proxy properties in rbx_reflector by using the injected plugin to set properties on each instance in a defaults place while listening for changes to any other properties that happen as a result. This will give us information about which proxy properties are linked to each other (for every property settable from Lua, or at least most of them) which we can include in the reflection database.

This does not solve the problem of how to convert to and from proxy properties - at this point that still has to be manual, but we should be able to get a complete picture of what proxy properties exist

@Dekkonot
Copy link
Member

I'm still not convinced that this would be useful, but this is a conversation for another issue

I think that's basically what we're headed for anyway, since we're finding a need to be aware of properties outside of the reflection database. I'm not saying it need to be a strongly typed DOM (I don't even know what that would look like) but we should seriously consider what the future looks like if we need to be aware of invariants and proxies inside rbx_dom_weak itself. If nothing else, there will need to be a layer on top of Instances that is aware of proxies for this to work automatically.

I think your proposal for cataloging them is fine, though brute-forcing properties feels gross. I tested it with Sound and it does correctly catch the proxied properties, at least those that are scriptable.

@phoriah
Copy link
Contributor

phoriah commented Jun 3, 2024

So anyway ... I think we can at least automate cataloguing proxy properties in rbx_reflector by using the injected plugin to set properties on each instance in a defaults place while listening for changes to any other properties that happen as a result. This will give us information about which proxy properties are linked to each other (for every property settable from Lua, or at least most of them) which we can include in the reflection database.

Adding onto this, this should get your almost a complete picture as it will expose NotScriptable proxies too. For example

local Part = Instance.new("Part")
Part.Changed:Connect(warn) --> BrickColor, Color, Color3uint8
Part.Color = Color3.new()

Also, here's a decent list (though probably incomplete) of NotScriptable proxies and their scriptable counterparts.
Do note that the list only consists of properties with CanLoad & CanSave being true.

NotScriptableProxies = {
    Players = { MaxPlayersInternal = "MaxPlayers", PreferredPlayersInternal = "PreferredPlayers" }, 
    -- DebuggerBreakpoint = {line="Line"}, -- ? This shouldn't appear in live games (try to prove this wrong)
    BallSocketConstraint = { MaxFrictionTorqueXml = "MaxFrictionTorque" },
    BasePart = {
        Color3uint8 = "Color",
        MaterialVariantSerialized = "MaterialVariant",
        size = "Size",
        _Inheritors = {
            TriangleMeshPart = {
                FluidFidelityInternal = "FluidFidelity",
                _Inheritors = {
                    MeshPart = { InitialSize = "MeshSize" },
                    PartOperation = { InitialSize = "MeshSize" },
                },
            },
            FormFactorPart = { formFactorRaw = "FormFactor", _Inheritors = { Part = { shape = "Shape" } } },

            TrussPart = { style = "Style" },
        },
    },
    -- CustomEvent = {PersistedCurrentValue=function(instance) -- * Class is Deprecated and :SetValue doesn't seem to affect GetCurrentValue anymore
    -- 	local Receiver  = instance:GetAttachedReceivers()[1]
    -- 	if Receiver then
    -- 		return Receiver:GetCurrentValue()
    -- 	else
    -- 		error("No Receiver")
    -- 	end
    -- end},

    DoubleConstrainedValue = { value = "Value" },
    IntConstrainedValue = { value = "Value" },
    Fire = { heat_xml = "Heat", size_xml = "Size" },

    Humanoid = { Health_XML = "Health" },
    MaterialService = { Use2022MaterialsXml = "Use2022Materials" },

    Model = {
        ScaleFactor = function(instance)
            return instance:GetScale()
        end,
        WorldPivotData = "WorldPivot",
        -- ModelMeshCFrame = "Pivot Offset",  -- * Both are NotScriptable
        -- _Inheritors = {
        -- 	Workspace = { SignalBehavior2 = "SignalBehavior" }, -- * Both are NotScriptable
        -- },
    },
    PackageLink = { PackageIdSerialize = "PackageId", VersionIdSerialize = "VersionNumber" },

    StarterPlayer = { AvatarJointUpgrade_Serialized = "AvatarJointUpgrade" },
    Smoke = { size_xml = "Size", opacity_xml = "Opacity", riseVelocity_xml = "RiseVelocity" },
    Sound = {
        xmlRead_MaxDistance_3 = "RollOffMaxDistance", -- * Also MaxDistance
    },
    -- ViewportFrame = { -- * Pointless because these reflect CurrentCamera's properties
    -- 	CameraCFrame = function(instance) -- *
    -- 		local CurrentCamera = instance.CurrentCamera
    -- 		if CurrentCamera then
    -- 			return CurrentCamera.CFrame
    -- 		else
    -- 			error("No CurrentCamera")
    -- 		end
    -- 	end,
    -- 	-- CameraFieldOfView =
    -- },
    WeldConstraint = {
        Part0Internal = "Part0",
        Part1Internal = "Part1",
        -- State = function(instance)
        -- 	-- If untouched then default state is 3 (default true)
        -- 	return instance.Enabled and 1 or 0
        -- end,
    },
}

Hopefully this helps! And, let me know if you discover any more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants