mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-24 06:35:39 +00:00
Intense robustness pass
This commit is contained in:
@@ -66,7 +66,9 @@ end
|
|||||||
function Plugin:restart()
|
function Plugin:restart()
|
||||||
warn("Rojo: The server has changed since the last request, reloading plugin...")
|
warn("Rojo: The server has changed since the last request, reloading plugin...")
|
||||||
|
|
||||||
self._reconciler:clear()
|
self._reconciler:destruct()
|
||||||
|
self._reconciler = Reconciler.new()
|
||||||
|
|
||||||
self._api = nil
|
self._api = nil
|
||||||
self._polling = false
|
self._polling = false
|
||||||
self._syncInProgress = false
|
self._syncInProgress = false
|
||||||
|
|||||||
@@ -1,13 +1,26 @@
|
|||||||
local RouteMap = require(script.Parent.RouteMap)
|
local RouteMap = require(script.Parent.RouteMap)
|
||||||
|
|
||||||
local function classEqual(rbx, className)
|
local function classEqual(a, b)
|
||||||
if className == "*" then
|
if a == "*" or b == "*" then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
return rbx.ClassName == className
|
return a == b
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function applyProperties(target, properties)
|
||||||
|
for key, property in pairs(properties) do
|
||||||
|
-- TODO: Transform property value based on property.Type
|
||||||
|
-- Right now, we assume that 'value' is primitive!
|
||||||
|
target[key] = property.Value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Attempt to parent `rbx` to `parent`, doing nothing if:
|
||||||
|
* parent is already `parent`
|
||||||
|
* Changing parent threw an error
|
||||||
|
]]
|
||||||
local function reparent(rbx, parent)
|
local function reparent(rbx, parent)
|
||||||
if rbx then
|
if rbx then
|
||||||
if rbx.Parent == parent then
|
if rbx.Parent == parent then
|
||||||
@@ -42,7 +55,7 @@ local function findNextChildPair(primaryChildren, secondaryChildren, visited)
|
|||||||
visited[primaryChild] = true
|
visited[primaryChild] = true
|
||||||
|
|
||||||
for _, secondaryChild in ipairs(secondaryChildren) do
|
for _, secondaryChild in ipairs(secondaryChildren) do
|
||||||
if primaryChild.ClassName == secondaryChild.ClassName and primaryChild.Name == secondaryChild.Name then
|
if classEqual(primaryChild.ClassName, secondaryChild.ClassName) and primaryChild.Name == secondaryChild.Name then
|
||||||
visited[secondaryChild] = true
|
visited[secondaryChild] = true
|
||||||
|
|
||||||
return primaryChild, secondaryChild
|
return primaryChild, secondaryChild
|
||||||
@@ -114,12 +127,11 @@ function Reconciler:_reify(item)
|
|||||||
local rbx = Instance.new(className)
|
local rbx = Instance.new(className)
|
||||||
rbx.Name = item.Name
|
rbx.Name = item.Name
|
||||||
|
|
||||||
for key, property in pairs(item.Properties) do
|
applyProperties(rbx, item.Properties)
|
||||||
-- TODO: Check for compound types, like Vector3!
|
|
||||||
rbx[key] = property.Value
|
|
||||||
end
|
|
||||||
|
|
||||||
self:_reconcileChildren(rbx, item)
|
for _, child in ipairs(item.Children) do
|
||||||
|
reparent(self:_reify(child), rbx)
|
||||||
|
end
|
||||||
|
|
||||||
if item.Route then
|
if item.Route then
|
||||||
self._routeMap:insert(item.Route, rbx)
|
self._routeMap:insert(item.Route, rbx)
|
||||||
@@ -129,10 +141,10 @@ function Reconciler:_reify(item)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Clears any state that the Reconciler has, effectively restarting it.
|
Clears any state that the Reconciler has, stopping it completely.
|
||||||
]]
|
]]
|
||||||
function Reconciler:clear()
|
function Reconciler:destruct()
|
||||||
self._routeMap:clear()
|
self._routeMap:destruct()
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@@ -156,28 +168,16 @@ function Reconciler:reconcile(rbx, item)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Item changed type!
|
-- Item changed type!
|
||||||
if not classEqual(rbx, item.ClassName) then
|
if not classEqual(rbx.ClassName, item.ClassName) then
|
||||||
self._routeMap:removeByRbx(rbx)
|
self._routeMap:removeByRbx(rbx)
|
||||||
rbx:Destroy()
|
rbx:Destroy()
|
||||||
|
|
||||||
return self:_reify(item)
|
return self:_reify(item)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Apply all properties, Roblox will de-duplicate changes
|
applyProperties(rbx, item.Properties)
|
||||||
for key, property in pairs(item.Properties) do
|
|
||||||
-- TODO: Transform property value based on property.Type
|
|
||||||
-- Right now, we assume that 'value' is primitive!
|
|
||||||
|
|
||||||
rbx[key] = property.Value
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use a dumb algorithm for reconciling children
|
|
||||||
self:_reconcileChildren(rbx, item)
|
self:_reconcileChildren(rbx, item)
|
||||||
|
|
||||||
if item.Route then
|
|
||||||
self._routeMap:insert(item.Route, rbx)
|
|
||||||
end
|
|
||||||
|
|
||||||
return rbx
|
return rbx
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ end
|
|||||||
function RouteMap:insert(route, rbx)
|
function RouteMap:insert(route, rbx)
|
||||||
local hashed = hashRoute(route)
|
local hashed = hashRoute(route)
|
||||||
|
|
||||||
|
-- Make sure that each route and instance are only present in RouteMap once.
|
||||||
|
self:removeByRoute(route)
|
||||||
|
self:removeByRbx(rbx)
|
||||||
|
|
||||||
self._map[hashed] = rbx
|
self._map[hashed] = rbx
|
||||||
self._reverseMap[rbx] = hashed
|
self._reverseMap[rbx] = hashed
|
||||||
self._connectionsByRbx[rbx] = rbx.AncestryChanged:Connect(function(_, parent)
|
self._connectionsByRbx[rbx] = rbx.AncestryChanged:Connect(function(_, parent)
|
||||||
@@ -42,26 +46,36 @@ function RouteMap:removeByRoute(route)
|
|||||||
local hashedRoute = hashRoute(route)
|
local hashedRoute = hashRoute(route)
|
||||||
local rbx = self._map[hashedRoute]
|
local rbx = self._map[hashedRoute]
|
||||||
|
|
||||||
if rbx then
|
if rbx ~= nil then
|
||||||
self._map[hashedRoute] = nil
|
self:_removeInternal(hashedRoute, rbx)
|
||||||
self._reverseMap[rbx] = nil
|
|
||||||
self._connectionsByRbx[rbx] = nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function RouteMap:removeByRbx(rbx)
|
function RouteMap:removeByRbx(rbx)
|
||||||
local hashedRoute = self._reverseMap[rbx]
|
local hashedRoute = self._reverseMap[rbx]
|
||||||
|
|
||||||
if hashedRoute then
|
if hashedRoute ~= nil then
|
||||||
self._map[hashedRoute] = nil
|
self:_removeInternal(hashedRoute, rbx)
|
||||||
self._reverseMap[rbx] = nil
|
|
||||||
self._connectionsByRbx[rbx] = nil
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Correcly removes the given Roblox Instance/Route pair from the RouteMap.
|
||||||
|
]]
|
||||||
|
function RouteMap:_removeInternal(rbx, hashedRoute)
|
||||||
|
self._map[hashedRoute] = nil
|
||||||
|
self._reverseMap[rbx] = nil
|
||||||
|
self._connectionsByRbx[rbx]:Disconnect()
|
||||||
|
self._connectionsByRbx[rbx] = nil
|
||||||
|
|
||||||
self:removeRbxDescendants(rbx)
|
self:removeRbxDescendants(rbx)
|
||||||
end
|
end
|
||||||
|
|
||||||
function RouteMap:removeRbxDescendants(parentRbx)
|
--[[
|
||||||
|
Ensure that there are no descendants of the given Roblox Instance still
|
||||||
|
present in the map, guaranteeing that it has been cleaned out.
|
||||||
|
]]
|
||||||
|
function RouteMap:_removeRbxDescendants(parentRbx)
|
||||||
for rbx in pairs(self._reverseMap) do
|
for rbx in pairs(self._reverseMap) do
|
||||||
if rbx:IsDescendantOf(parentRbx) then
|
if rbx:IsDescendantOf(parentRbx) then
|
||||||
self:removeByRbx(rbx)
|
self:removeByRbx(rbx)
|
||||||
@@ -69,7 +83,11 @@ function RouteMap:removeRbxDescendants(parentRbx)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function RouteMap:clear()
|
--[[
|
||||||
|
Remove all items from the map and disconnect all connections, cleaning up
|
||||||
|
the RouteMap.
|
||||||
|
]]
|
||||||
|
function RouteMap:destruct()
|
||||||
self._map = {}
|
self._map = {}
|
||||||
self._reverseMap = {}
|
self._reverseMap = {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user