From b86d1efc022bfe98ee45ed8f3fafa4b526d178aa Mon Sep 17 00:00:00 2001 From: hoontee Date: Tue, 12 Nov 2024 04:34:18 -0600 Subject: [PATCH] Split InstanceStream into Server and Client variants --- Pronghorn/New.luau | 147 ++++++++++++++++++++------------------------ Pronghorn/init.luau | 2 +- README.md | 9 +-- 3 files changed, 72 insertions(+), 86 deletions(-) diff --git a/Pronghorn/New.luau b/Pronghorn/New.luau index 58b2892..ec029d9 100644 --- a/Pronghorn/New.luau +++ b/Pronghorn/New.luau @@ -91,7 +91,7 @@ end --- @param parent? -- The Parent for the Instance after creation. --- @param name? -- The Name for the Instance. --- @param properties? -- A table of properties to apply to the Instance. ---- @return Instance -- The new Instance. +--- @return any -- The new Instance. --- @error Parent parameter used more than once -- Incorrect usage. --- @error Name parameter used more than once -- Incorrect usage. --- @error Properties parameter used more than once -- Incorrect usage. @@ -130,7 +130,7 @@ end --- @param parent? -- The Parent for the cloned Instance after creation. --- @param name? -- The Name for the cloned Instance. --- @param properties? -- A table of properties to apply to the cloned Instance. ---- @return Instance -- The cloned Instance. +--- @return T -- The cloned Instance. --- @error Attempt to clone non-Instance -- Incorrect usage. --- @error Parent parameter used more than once -- Incorrect usage. --- @error Name parameter used more than once -- Incorrect usage. @@ -168,7 +168,7 @@ function New.Clone(instance: T, ...: (Instance | string | Properties)?): T end --- Creates and returns an Event. ---- @return Event -- The new Event. +--- @return Event<...any> -- The new Event. function New.Event(): Event<...any> local callbacks: {Callback<...any>} = {} local waiting: {Callback<...any> | thread} = {} @@ -235,7 +235,7 @@ end --- Creates and returns a QueuedEvent. --- @param nameHint? -- The name of the QueuedEvent for debugging. ---- @return QueuedEvent -- The new QueuedEvent. +--- @return Event<...any> -- The new QueuedEvent. function New.QueuedEvent(nameHint: string?): Event<...any> local callbacks: {Callback<...any>} = {} local waiting: {Callback<...any> | thread} = {} @@ -334,7 +334,7 @@ end --- Creates and returns a TrackedVariable. --- @param variable -- The initial value of the TrackedVariable. ---- @return TrackedVariable -- The new TrackedVariable. +--- @return TrackedVariable -- The new TrackedVariable. function New.TrackedVariable(variable: any): TrackedVariable local callbacks: {Callback} = {} local waiting: {Callback | thread} = {} @@ -407,91 +407,80 @@ function New.TrackedVariable(variable: any): TrackedVariable return actions end ---- Creates and returns an InstanceStream. ---- @return InstanceStream -- The new InstanceStream. -function New.InstanceStream(): InstanceStream<...any> - local replicators: {[Player]: RemoteEvent} = {} +--- Starts a ServerInstanceStream and returns its UID. +--- @return string -- The UID of the ServerInstanceStream. +function New.ServerInstanceStream(players: Player | {Player}, instances: {Instance}): string + if IS_CLIENT then error("ServerInstanceStream cannot be created on the client", 0) end - local actions: InstanceStream<...Instance> = { - Instances = {}; + local uid = `{HttpService:GenerateGUID(false)}_{#instances}` - Start = function(self: InstanceStream<...Instance>, players: Player | {Player}, instances: {Instance}): string - if IS_CLIENT then error("InstanceStream.Start cannot be called on the client", 0) end + for _, player in (if type(players) == "table" then players else {players}) :: {Player} do + if not player.Parent then continue end - table.clear(self.Instances) - for index, instance in instances do - self.Instances[index] = instance - end - - local uid = `{HttpService:GenerateGUID(false)}_{#instances}` - - for _, player in (if type(players) == "table" then players else {players}) :: {Player} do - if not player.Parent then continue end - - local replicator = New.Instance("RemoteEvent", `__instanceStream_{uid}`) :: RemoteEvent + local replicator = New.Instance("RemoteEvent", `__instanceStream_{uid}`) :: RemoteEvent - if replicators[player] then - replicators[player]:Destroy() - end - replicators[player] = replicator - - for _, instance in instances do - New.Instance("ObjectValue", replicator, {Value = instance}) - end + for _, instance in instances do + New.Instance("ObjectValue", replicator, {Value = instance}) + end - replicator.OnServerEvent:Once(function() - replicator:Destroy() - replicators[player] = nil - end) + replicator.OnServerEvent:Once(function() + replicator:Destroy() + end) - replicator.Parent = player.PlayerGui - end + replicator.Parent = player.PlayerGui + task.delay(10, replicator.Destroy, replicator) + end - return uid - end; + return uid +end - Listen = function(self: InstanceStream<...Instance>, uid: string): (Event<...Instance>, Event) - if IS_SERVER then error("InstanceStream.Listen cannot be called on the server", 0) end - - local container = assert(localPlayer.PlayerGui:FindFirstChild("__instanceStream_" .. uid), `Cannot find InstanceStream with UID '{uid}'`) :: RemoteEvent - local numInstances = assert(tonumber(uid:split("_")[2])) - local finishedEvent: Event<...Instance> = New.QueuedEvent("InstanceStream Finished Event") - local streamEvent: Event = New.QueuedEvent("InstanceStream Stream Event") - - for _, child in container:GetChildren() do - assert(child:IsA("ObjectValue")) - if child.Value then - table.insert(self.Instances, child.Value) - streamEvent:Fire(child.Value) - else - child.Changed:Once(function() - assert(child.Value) - table.insert(self.Instances, child.Value) - streamEvent:Fire(child.Value) - end) - end - end +--- Listens to a ServerInstanceStream and returns activity Events. +--- @return Event<...any> -- The Event that fires when the stream has finished. +--- @return Event -- The Event that fires when an Instance is received. +function New.ClientInstanceStream(uid: string): (Event<...any>, Event) + if IS_SERVER then error("ClientInstanceStream cannot be created on the server", 0) end + + local replicator = assert(localPlayer.PlayerGui:FindFirstChild("__instanceStream_" .. uid), `Cannot find InstanceStream with UID '{uid}'`) :: RemoteEvent + local numInstances = assert(tonumber(uid:split("_")[2])) + local instances: {Instance} = {} + local finishedEvent: Event<...Instance> = New.QueuedEvent("InstanceStream Finished Event") + local streamEvent: Event = New.QueuedEvent("InstanceStream Stream Event") + + replicator.Destroying:Connect(function() + finishedEvent:DisconnectAll() + streamEvent:DisconnectAll() + end) + + for _, child in replicator:GetChildren() do + assert(child:IsA("ObjectValue")) + if child.Value then + table.insert(instances, child.Value) + streamEvent:Fire(child.Value) + else + child.Changed:Once(function() + assert(child.Value) + table.insert(instances, child.Value) + streamEvent:Fire(child.Value) + end) + end + end - if #container:GetChildren() == numInstances then - finishedEvent:Fire(table.unpack(self.Instances)) - container:FireServer() - else - container.ChildAdded:Connect(function(child: Instance) - assert(child:IsA("ObjectValue") and (child.Value or child.Changed:Wait() and child.Value)) - table.insert(self.Instances, child.Value) - streamEvent:Fire(child) - if #container:GetChildren() == numInstances then - finishedEvent:Fire(table.unpack(self.Instances)) - container:FireServer() - end - end) + if #replicator:GetChildren() == numInstances then + finishedEvent:Fire(table.unpack(instances)) + replicator:FireServer() + else + replicator.ChildAdded:Connect(function(child: Instance) + assert(child:IsA("ObjectValue") and (child.Value or child.Changed:Wait() and child.Value)) + table.insert(instances, child.Value) + streamEvent:Fire(child) + if #replicator:GetChildren() == numInstances then + finishedEvent:Fire(table.unpack(instances)) + replicator:FireServer() end + end) + end - return finishedEvent, streamEvent - end; - } - - return actions + return finishedEvent, streamEvent end -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Pronghorn/init.luau b/Pronghorn/init.luau index 55ced08..00cbe54 100644 --- a/Pronghorn/init.luau +++ b/Pronghorn/init.luau @@ -31,7 +31,7 @@ ║ ██████▀██▓▌▀▌ ▄ ▄▓▌▐▓█▌ ║ ║ ║ ║ ║ -║ Pronghorn Framework Rev. B74 ║ +║ Pronghorn Framework Rev. B75 ║ ║ https://github.com/Iron-Stag-Games/Pronghorn ║ ║ GNU Lesser General Public License v2.1 ║ ║ ║ diff --git a/README.md b/README.md index ddbf052..786043a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Trace(...) ## New ```luau -New.Instance(className: string, parent: Instance?, name: string?, properties: {[string]: any, children: {Instance}?, attributes: {[string]: any}?, tags: {string}?}?): Instance +New.Instance(className: string, parent: Instance?, name: string?, properties: {[string]: any, children: {Instance}?, attributes: {[string]: any}?, tags: {string}?}?): any New.Clone(instance: T, parent: Instance?, name: string?, properties: {[string]: any, children: {Instance}?, attributes: {[string]: any}?, tags: {string}?}?): T -- New.Instance / New.Clone -- Parent, Name, and Properties optional parameters can be provided in any combination and order. @@ -69,11 +69,8 @@ New.TrackedVariable(variable: any): TrackedVariable = { Wait: (self: TrackedVariable) -> (T, T) & (self: TrackedVariable, timeout: number) -> (T?, T?); DisconnectAll: (self: TrackedVariable) -> (); } -New.InstanceStream(): InstanceStream = { - Instances: {Instance}; - Start: (self: InstanceStream, players: Player | {Player}, instances: {Instance}) -> (string); - Listen: (self: InstanceStream, uid: string) -> (Event, Event); -} +New.ServerInstanceStream(players: Player | {Player}, instances: {Instance}): string +New.ClientInstanceStream(): (Event, Event) ``` ## Remotes