forked from rojo-rbx/rojo
* Implement ChangeBatcher * Use ChangeBatcher for two-way sync * Pause updates during patch application * I can English good * Break after encountering a nil Parent change This prevents __flush from erroring out when an instance's Parent is changed to nil and it has other property changes in the same batch. * Update rbx_dom_lua * Don't connect changed listeners in a running game #468 made me realize how bad of an idea this is in general... * Update TestEZ and fix sibling Ref reification test * Add ChangeBatcher tests * Test instance unpausing by breaking functionality out to __cycle * Break up the module a bit and improve tests * Shuffle requires around and edit comment * Break out more stuff, rename createChangePatch -> createPatchSet * Make ChangeBatcher responsible for unpausing all paused instances This somewhat improves the situation (of course, it would preferrable to not have to hack around this problem with Source at all). It also sets us up nicely if we come across any other properties that do anything similar. * Remove old reference to pausedBatchInstances * Use RenderStepped instead of Heartbeat and trash multi-frame pauses I probably should have done this in the first place... ChangeBatcher still needs to unpause instances, but we don't need to hold pauses for any longer than one cycle. * Remove useless branch * if not next(x) -> if next(x) == nil * Add InstanceMap:unpauseAllInstances, use it in ChangeBatcher * Move IsRunning check to InstanceMap:__maybeFireInstanceChanged
95 lines
2.8 KiB
Lua
95 lines
2.8 KiB
Lua
local Error = require(script.Parent.Error)
|
|
local customProperties = require(script.Parent.customProperties)
|
|
|
|
-- A wrapper around a property descriptor from the reflection database with some
|
|
-- extra convenience methods.
|
|
--
|
|
-- The aim of this API is to facilitate looking up a property once, then reading
|
|
-- from it or writing to it multiple times. It's also useful when a consumer
|
|
-- wants to check additional constraints on the property before trying to use
|
|
-- it, like scriptability.
|
|
local PropertyDescriptor = {}
|
|
PropertyDescriptor.__index = PropertyDescriptor
|
|
|
|
local function get(container, key)
|
|
return container[key]
|
|
end
|
|
|
|
local function set(container, key, value)
|
|
container[key] = value
|
|
end
|
|
|
|
function PropertyDescriptor.fromRaw(data, className, propertyName)
|
|
local key, value = next(data.DataType)
|
|
|
|
return setmetatable({
|
|
-- The meanings of the key and value in DataType differ when the type of
|
|
-- the property is Enum. When the property is of type Enum, the key is
|
|
-- the name of the type:
|
|
--
|
|
-- { Enum = "<name of enum>" }
|
|
--
|
|
-- When the property is not of type Enum, the value is the name of the
|
|
-- type:
|
|
--
|
|
-- { Value = "<data type>" }
|
|
dataType = key == "Enum" and key or value,
|
|
|
|
scriptability = data.Scriptability,
|
|
className = className,
|
|
name = propertyName,
|
|
}, PropertyDescriptor)
|
|
end
|
|
|
|
function PropertyDescriptor:read(instance)
|
|
if self.scriptability == "ReadWrite" or self.scriptability == "Read" then
|
|
local success, value = xpcall(get, debug.traceback, instance, self.name)
|
|
|
|
if success then
|
|
return success, value
|
|
else
|
|
return false, Error.new(Error.Kind.Roblox, value)
|
|
end
|
|
end
|
|
|
|
if self.scriptability == "Custom" then
|
|
local interface = customProperties[self.className][self.name]
|
|
|
|
return interface.read(instance, self.name)
|
|
end
|
|
|
|
if self.scriptability == "None" or self.scriptability == "Write" then
|
|
local fullName = ("%s.%s"):format(instance.className, self.name)
|
|
|
|
return false, Error.new(Error.Kind.PropertyNotReadable, fullName)
|
|
end
|
|
|
|
error(("Internal error: unexpected value of 'scriptability': %s"):format(tostring(self.scriptability)), 2)
|
|
end
|
|
|
|
function PropertyDescriptor:write(instance, value)
|
|
if self.scriptability == "ReadWrite" or self.scriptability == "Write" then
|
|
local success, err = xpcall(set, debug.traceback, instance, self.name, value)
|
|
|
|
if success then
|
|
return success
|
|
else
|
|
return false, Error.new(Error.Kind.Roblox, err)
|
|
end
|
|
end
|
|
|
|
if self.scriptability == "Custom" then
|
|
local interface = customProperties[self.className][self.name]
|
|
|
|
return interface.write(instance, self.name, value)
|
|
end
|
|
|
|
if self.scriptability == "None" or self.scriptability == "Read" then
|
|
local fullName = ("%s.%s"):format(instance.className, self.name)
|
|
|
|
return false, Error.new(Error.Kind.PropertyNotWritable, fullName)
|
|
end
|
|
end
|
|
|
|
return PropertyDescriptor
|