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 b86d1ef
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 86 deletions.
147 changes: 68 additions & 79 deletions Pronghorn/New.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -168,7 +168,7 @@ function New.Clone<T>(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} = {}
Expand Down Expand Up @@ -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} = {}
Expand Down Expand Up @@ -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<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,80 @@ 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.
--- @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<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.
--- @return Event<...any> -- The Event that fires when the stream has finished.
--- @return Event<any> -- The Event that fires when an Instance is received.
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
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(): (Event<T...>, Event<U>)
```

## Remotes
Expand Down

0 comments on commit b86d1ef

Please sign in to comment.