Skip to content

Commit

Permalink
Split InstanceStream into Server and Client variants
Browse files Browse the repository at this point in the history
  • Loading branch information
hoontee committed Nov 12, 2024
1 parent c2334ac commit 4078f4d
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 113 deletions.
190 changes: 94 additions & 96 deletions Pronghorn/New.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(instance: T, properties: Properties): ()
assert(typeof(instance) == "Instance", "Attempt to apply properties to a non-Instance")

Expand All @@ -87,11 +87,11 @@ function New.Properties<T>(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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -167,8 +167,8 @@ function New.Clone<T>(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} = {}
Expand Down Expand Up @@ -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} = {}
Expand Down Expand Up @@ -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<any> -- The new `TrackedVariable`.
function New.TrackedVariable(variable: any): TrackedVariable<any>
local callbacks: {Callback<any, any>} = {}
local waiting: {Callback<any, any> | thread} = {}
Expand Down Expand Up @@ -407,91 +407,89 @@ function New.TrackedVariable(variable: any): TrackedVariable<any>
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<Instance>)
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<Instance> = 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<any> -- 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<any>)
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<Instance> = 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

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
20 changes: 10 additions & 10 deletions Pronghorn/Remotes/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Pronghorn/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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 ║
║ ║
Expand Down
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -69,11 +69,8 @@ New.TrackedVariable(variable: any): TrackedVariable<T> = {
Wait: (self: TrackedVariable<T>) -> (T, T) & (self: TrackedVariable<T>, timeout: number) -> (T?, T?);
DisconnectAll: (self: TrackedVariable<T>) -> ();
}
New.InstanceStream(): InstanceStream<T...> = {
Instances: {Instance};
Start: (self: InstanceStream<T...>, players: Player | {Player}, instances: {Instance}) -> (string);
Listen: (self: InstanceStream<T...>, uid: string) -> (Event<T...>, Event<Instance>);
}
New.ServerInstanceStream(players: Player | {Player}, instances: {Instance}): string
New.ClientInstanceStream(uid: string): (Event<T...>, Event<U>)
```

## Remotes
Expand Down

0 comments on commit 4078f4d

Please sign in to comment.