diff --git a/Pronghorn/New.luau b/Pronghorn/New.luau index 58b2892..442daf4 100644 --- a/Pronghorn/New.luau +++ b/Pronghorn/New.luau @@ -59,9 +59,9 @@ local localPlayer = Players.LocalPlayer -- Module Functions -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Applies properties, attributes, tags, callbacks, and children to an Instance. ---- @param instance -- The Instance to apply to. ---- @param properties -- A table of properties to apply to the Instance. +--- Applies properties, attributes, tags, callbacks, and children to an `Instance`. +--- @param instance -- The `Instance` to apply to. +--- @param properties -- A table of properties to apply to the `Instance`. function New.Properties(instance: T, properties: Properties): () assert(typeof(instance) == "Instance", "Attempt to apply properties to a non-Instance") @@ -87,11 +87,11 @@ function New.Properties(instance: T, properties: Properties): () end --- Creates and returns a new Instance. ---- @param className -- The ClassName for the Instance being created. ---- @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. +--- @param className -- The `ClassName` for the `Instance` being created. +--- @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 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. @@ -125,12 +125,12 @@ function New.Instance(className: string, ...: (Instance | string | Properties)?) return newInstance end ---- Clones and returns an Instance. ---- @param instance -- The Instance to clone from. ---- @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. +--- Clones and returns an `Instance`. +--- @param instance -- The `Instance` to clone from. +--- @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 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. @@ -167,8 +167,8 @@ function New.Clone(instance: T, ...: (Instance | string | Properties)?): T return newInstance end ---- Creates and returns an Event. ---- @return Event -- The new Event. +--- Creates and returns an `Event`. +--- @return Event<...any> -- The new `Event`. function New.Event(): Event<...any> local callbacks: {Callback<...any>} = {} local waiting: {Callback<...any> | thread} = {} @@ -233,9 +233,9 @@ function New.Event(): Event<...any> return actions end ---- Creates and returns a QueuedEvent. ---- @param nameHint? -- The name of the QueuedEvent for debugging. ---- @return QueuedEvent -- The new QueuedEvent. +--- Creates and returns a `QueuedEvent`. +--- @param nameHint? -- The name of the `QueuedEvent` for debugging. +--- @return Event<...any> -- The new `QueuedEvent`. function New.QueuedEvent(nameHint: string?): Event<...any> local callbacks: {Callback<...any>} = {} local waiting: {Callback<...any> | thread} = {} @@ -332,9 +332,9 @@ function New.QueuedEvent(nameHint: string?): Event<...any> return actions end ---- Creates and returns a TrackedVariable. ---- @param variable -- The initial value of the TrackedVariable. ---- @return TrackedVariable -- The new TrackedVariable. +--- Creates and returns a `TrackedVariable`. +--- @param variable -- The initial value of the `TrackedVariable`. +--- @return TrackedVariable -- The new T`rackedVariable`. function New.TrackedVariable(variable: any): TrackedVariable local callbacks: {Callback} = {} local waiting: {Callback | thread} = {} @@ -407,91 +407,89 @@ 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. +--- @param players -- The list of `Players` to stream `Instances` to. +--- @param instances -- The list of `Instances` to stream. +--- @param clone? -- Whether or not to clone the list of `Instances` into `PlayerGui`. +--- @return string -- The UID of the `ServerInstanceStream`. +--- @error ServerInstanceStream cannot be created on the client -- Incorrect usage. +function New.ServerInstanceStream(players: Player | {Player}, instances: {Instance}, clone: boolean?): 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 + if clone then + instance = instance:Clone() + end + New.Instance("ObjectValue", replicator, {Value = instance, Children = if clone then {instance} else nil}) + 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`. +--- @param uid -- The UID of the `ServerInstanceStream`. +--- @return Event<...any> -- The `Event` that fires when the `ClientInstanceStream` has received all `Instances`. +--- @return Event -- The `Event` that fires when an `Instance` is received. +--- @error ClientInstanceStream cannot be created on the server -- Incorrect usage. +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/Remotes/init.luau b/Pronghorn/Remotes/init.luau index 00f7f37..76a6518 100644 --- a/Pronghorn/Remotes/init.luau +++ b/Pronghorn/Remotes/init.luau @@ -121,11 +121,11 @@ end -- Module Functions -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Creates a Remote that sends information to Clients. ---- @param name -- The name of the Remote. ---- @param requiredParameterTypes -- The required types for parameters. Accepts ClassName, EnumItem, any, ..., ?, and |. ---- @param remoteType? -- Whether the Remote is unreliable, reliable, or yields and returns a value. ---- @return GenericRemote -- The new Remote. +--- Creates a `Remote` that sends information to clients. +--- @param name -- The name of the `Remote`. +--- @param requiredParameterTypes -- The required types for parameters. Accepts `ClassName`, `EnumItem`, `any`, `...`, `?`, and `|`. +--- @param remoteType? -- Whether the `Remote` is unreliable, reliable, or yields and returns a value. +--- @return ServerRemote -- The new `Remote`. --- @error Remotes cannot be created on the client -- Incorrect usage. --- @error Remotes.CreateToClient: Parameter 'requiredParameterTypes' expected type '{string}', got '{typeof(requiredParameterTypes)}' -- Incorrect usage. --- @error Remotes.CreateToClient: Parameter 'remoteType' expected 'nil | Unreliable" | "Reliable" | "Returns"', got '{remoteType}' -- Incorrect usage. @@ -193,12 +193,12 @@ function Remotes.Server:CreateToClient(name: string, requiredParameterTypes: {st return actions end ---- Creates a Remote that receives information from Clients. ---- @param name -- The name of the Remote. ---- @param requiredParameterTypes -- The required types for parameters. Accepts ClassName, EnumItem, any, ..., ?, and |. ---- @param remoteType? -- Whether the Remote is unreliable, reliable, or yields and returns a value. +--- Creates a `Remote` that receives information from clients. +--- @param name -- The name of the `Remote`. +--- @param requiredParameterTypes -- The required types for parameters. Accepts `ClassName`, `EnumItem`, `any`, `...`, `?`, and `|`. +--- @param remoteType? -- Whether the `Remote` is unreliable, reliable, or yields and returns a value. --- @param func -- The listener function to be invoked. ---- @return GenericRemote -- The new Remote. +--- @return `ServerRemote` -- The new Remote. --- @error Remotes cannot be created on the client -- Incorrect usage. --- @error Remotes.CreateToClient: Parameter 'requiredParameterTypes' expected type '{string}', got '{typeof(requiredParameterTypes)}' -- Incorrect usage. --- @error Remotes.CreateToClient: Parameter 'remoteType' expected 'nil | Unreliable" | "Reliable" | "Returns"', got '{remoteType}' -- Incorrect usage. 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..f3a960f 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(uid: string): (Event, Event) ``` ## Remotes