From 31b352110c20cccfbcaf11876d18118caf6071cd Mon Sep 17 00:00:00 2001 From: utrain Date: Thu, 8 Dec 2022 19:47:57 -0500 Subject: [PATCH] Fixed CreatePart and Clone failing to work under Content Streaming By using tags, we can wait for the parts to replicate in. Right now, F3X falters at creating/cloning parts with content streaming. This is because the code assumes that the instances will instantly replicate, which is no longer true with content streaming. Hence, the list of parts the client receives from the server becomes empty, despite being created on the server. So, from the server, we give the client a tag to listen to for the newly made parts. Most times, it shouldn't need to wait for the parts to come. But, with enough parts being cloned, it may need to wait for several chunks. However, sometimes the parts will never stream in if far enough, so simply best to give up after a reasonable amount of time. --- Core/init.lua | 28 +++++++++++++++++++++++++--- SyncAPI.lua | 17 ++++++++++++----- Tools/NewPart.lua | 28 +++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/Core/init.lua b/Core/init.lua index 25a2763..788b398 100644 --- a/Core/init.lua +++ b/Core/init.lua @@ -31,6 +31,7 @@ local Cryo = require(Tool.Libraries:WaitForChild('Cryo')) Support.ImportServices(); SyncAPI = Tool.SyncAPI; Player = Players.LocalPlayer; +local CollectionService = game:GetService("CollectionService") local RunService = game:GetService('RunService') -- Preload assets @@ -157,7 +158,6 @@ Enabled = Signal.new() Disabled = Signal.new() function Enable(Mouse) - -- Ensure tool is disabled or disabling, and not already enabling if (IsEnabled and not IsDisabling) or IsEnabling then return; @@ -549,12 +549,34 @@ function CloneSelection() -- Clones selected parts -- Make sure that there are items in the selection - if #Selection.Items == 0 then + local AmountSelected = #Selection.Items + + if AmountSelected == 0 then return; end; -- Send the cloning request to the server - local Clones = SyncAPI:Invoke('Clone', Selection.Items, GetHighestParent(Selection.Items)) + local CloneTag = SyncAPI:Invoke('Clone', Selection.Items, GetHighestParent(Selection.Items)) + + -- Attempt to collect all the clones + + -- Strong chance that by now, most of the cloned objects would've of replicated. + local Clones = CollectionService:GetTagged(CloneTag) + + -- However, with enough cloned parts, it's possible they would've of missed. + local Connection = CollectionService:GetInstanceAddedSignal(CloneTag):Connect(function(Object) + table.insert(Clones, Object) + end) + + -- Wait for all the instances to be collected. + local TotalWaited = 0 + + -- At most, wait for half of a second for all of them. Otherwise, they likely out of range. + while #Clones ~= AmountSelected and TotalWaited <= 0.5 do + TotalWaited += task.wait() + end + + Connection:Disconnect() -- Put together the history record local HistoryRecord = { diff --git a/SyncAPI.lua b/SyncAPI.lua index 4db97e9..575dbf1 100644 --- a/SyncAPI.lua +++ b/SyncAPI.lua @@ -1,3 +1,4 @@ +local CollectionService = game:GetService("CollectionService") local HttpService = game:GetService('HttpService') local RunService = game:GetService('RunService') @@ -57,19 +58,21 @@ Actions = { end local Clones = {} + local CloneTag = string.format("F3X:%s", HttpService:GenerateGUID()) -- Clone items for _, Item in pairs(Items) do local Clone = Item:Clone() Clone.Parent = Parent - + CollectionService:AddTag(Clone, CloneTag) + -- Register the clone table.insert(Clones, Clone) CreatedInstances[Item] = Item end - - -- Return the clones - return Clones + + -- Return tag the clones will have + return CloneTag end; ['CreatePart'] = function (PartType, Position, Parent) @@ -99,8 +102,12 @@ Actions = { -- Register the part CreatedInstances[NewPart] = NewPart; + -- Create the tag to watch for. + local NewPartTag = string.format("F3X:%s", HttpService:GenerateGUID()) + CollectionService:AddTag(NewPart, NewPartTag) + -- Return the part - return NewPart; + return NewPartTag; end; ['CreateGroup'] = function (Type, Parent, Items) diff --git a/Tools/NewPart.lua b/Tools/NewPart.lua index de0c213..d7c1921 100644 --- a/Tools/NewPart.lua +++ b/Tools/NewPart.lua @@ -5,6 +5,7 @@ local UI = Tool:WaitForChild('UI') local Libraries = Tool:WaitForChild('Libraries') -- Services +local CollectionService = game:GetService("CollectionService") local ContextActionService = game:GetService 'ContextActionService' -- Libraries @@ -179,13 +180,30 @@ end; function CreatePart(Type) -- Send the creation request to the server - local Part = Core.SyncAPI:Invoke('CreatePart', Type, CFrame.new(Core.Mouse.Hit.p), Core.Targeting.Scope) + local PartTag = Core.SyncAPI:Invoke('CreatePart', Type, CFrame.new(Core.Mouse.Hit.p), Core.Targeting.Scope) - -- Make sure the part creation succeeds - if not Part then - return; - end; + -- Try getting the part the first time. + local Part = CollectionService:GetTagged(PartTag)[1] + if not Part then + -- Let's try waiting for the part to stream in. + local Connection = CollectionService:GetInstanceAddedSignal(PartTag):Once(function(Object) + Part = Object + end) + + -- Try waiting for the part's existence. + local TotalWaited = 0 + while not Part and TotalWaited <= 0.5 do + TotalWaited += task.wait() + end + + -- If there still wasn't a part, then it's probably out of range. + if not Part then + Connection:Disconnect() + return + end + end + -- Put together the history record local HistoryRecord = { Part = Part;