Skip to content

Commit 6331644

Browse files
authored
Merge pull request #1 from UnnamedCorp/v2
2 parents 2c5bd4e + 07c7002 commit 6331644

File tree

1 file changed

+221
-113
lines changed

1 file changed

+221
-113
lines changed

Overture.module.lua

Lines changed: 221 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,152 +1,260 @@
1+
--!nonstrict
12
--// Initialization
23

34
local RunService = game:GetService("RunService")
45
local PlayerService = game:GetService("Players")
56
local StarterPlayer = game:GetService("StarterPlayer")
6-
local CollectionService = game:GetService("CollectionService")
77
local ReplicatedStorage = game:GetService("ReplicatedStorage")
8-
local ServerScriptService = game:GetService("ServerScriptService")
9-
10-
local IsClient = RunService:IsClient()
11-
local IsServer = RunService:IsServer()
8+
local CollectionService = game:GetService("CollectionService")
9+
local StarterCharacterScripts = StarterPlayer:WaitForChild("StarterCharacterScripts"):: Folder
1210

1311
local Module = {}
14-
local CollectionMetatable = {}
12+
local LibraryThreadCache: {[thread]: string} = {}
13+
local Libraries: {[string]: ModuleScript} = {}
1514

16-
--// Variables
15+
--// Functions
1716

18-
local DebugPrint = false
17+
local function Retrieve(InstanceName: string, InstanceClass: string, InstanceParent: Instance, ForceWait: boolean?): Instance
18+
if ForceWait then
19+
return InstanceParent:WaitForChild(InstanceName)
20+
end
1921

20-
local RetrievalSets = {
21-
["RemoteEvent"] = "RemoteEvent",
22-
["RemoteFunction"] = "RemoteFunction",
23-
["BindableEvent"] = "BindableEvent",
24-
["BindableFunction"] = "BindableFunction",
25-
}
22+
local SearchInstance = InstanceParent:FindFirstChild(InstanceName)
2623

27-
--// Functions
24+
if not SearchInstance then
25+
SearchInstance = Instance.new(InstanceClass)
26+
SearchInstance.Name = InstanceName
27+
SearchInstance.Parent = InstanceParent
28+
end
29+
30+
return SearchInstance
31+
end
2832

29-
local function printd(...)
30-
if DebugPrint then
31-
return print(...)
33+
function Module._BindFunction(Function: (Instance) -> (), Event: RBXScriptSignal, Existing: {Instance}): RBXScriptConnection
34+
if Existing then
35+
for _, Value in next, Existing do
36+
task.spawn(Function, Value)
37+
end
3238
end
39+
40+
return Event:Connect(Function)
41+
end
42+
43+
function Module._BindToTag(Tag: string, Function: (Instance) -> ())
44+
return Module._BindFunction(Function, CollectionService:GetInstanceAddedSignal(Tag), CollectionService:GetTagged(Tag))
3345
end
3446

35-
local function Retrieve(InstanceName, InstanceClass, InstanceParent)
36-
--/ Finds an Instance by name and creates a new one if it doesen't exist
37-
38-
local SearchInstance = nil
39-
local InstanceCreated = false
40-
41-
if InstanceParent:FindFirstChild(InstanceName) then
42-
SearchInstance = InstanceParent[InstanceName]
47+
function Module:LoadLibrary(Index: string)
48+
if Libraries[Index] then
49+
return require(Libraries[Index])
4350
else
44-
InstanceCreated = true
45-
SearchInstance = Instance.new(InstanceClass)
46-
SearchInstance.Name = InstanceName
47-
SearchInstance.Parent = InstanceParent
51+
assert(not RunService:IsServer(), "The library \"" .. Index .. "\" does not exist!")
52+
53+
LibraryThreadCache[coroutine.running()] = Index
54+
return require(coroutine.yield())
4855
end
49-
50-
return SearchInstance, InstanceCreated
5156
end
5257

53-
local function BindToTag(Tag, Callback)
54-
CollectionService:GetInstanceAddedSignal(Tag):Connect(Callback)
55-
56-
for _, TaggedItem in next, CollectionService:GetTagged(Tag) do
57-
Callback(TaggedItem)
58+
function Module:LoadLibraryOnClient(...)
59+
if RunService:IsClient() then
60+
return self:LoadLibrary(...)
5861
end
5962
end
6063

61-
function CollectionMetatable:__newindex(Index, Value)
62-
rawset(self, Index, Value)
63-
if Index:sub(1, 1) == "_" then return end
64-
65-
for BindableEvent, ExpectedIndex in next, self._WaitCache do
66-
if Index == ExpectedIndex then
67-
spawn(function()
68-
BindableEvent:Fire(Value)
69-
BindableEvent:Destroy()
70-
end)
71-
end
64+
function Module:LoadLibraryOnServer(...)
65+
if RunService:IsServer() then
66+
return self:LoadLibrary(...)
7267
end
7368
end
7469

75-
do Module.Libraries = setmetatable({}, CollectionMetatable)
76-
Module.Libraries._Folder = Retrieve("Libraries", "Folder", ReplicatedStorage)
77-
Module.Libraries._WaitCache = {}
78-
79-
BindToTag("oLibrary", function(Object)
80-
Module.Libraries[Object.Name] = Object
81-
82-
if CollectionService:HasTag(Object, "ForceReplicate") then
83-
Object.Parent = Module.Libraries._Folder
84-
end
85-
end)
86-
87-
function Module:LoadLibrary(Index)
88-
if self.Libraries[Index] then
89-
return require(self.Libraries[Index])
90-
else
91-
assert(IsClient, "The library \"" .. Index .. "\" does not exist!")
92-
printd("The client is yielding for the library \"" .. Index .. "\".")
93-
94-
--/ Coroutine yielding has been temporarily replaced with BindableEvents due to Roblox issues.
95-
96-
local BindableEvent = Instance.new("BindableEvent")
97-
BindableEvent.Parent = script
98-
99-
self.Libraries._WaitCache[BindableEvent] = Index
100-
return require(BindableEvent.Event:Wait())
101-
end
70+
function Module:GetLocal(InstanceClass: string, InstanceName: string): Instance
71+
return Retrieve(InstanceName, InstanceClass, (Retrieve("Local" .. InstanceClass, "Folder", script)))
72+
end
73+
74+
function Module:WaitFor(InstanceClass: string, InstanceName: string): Instance
75+
return Retrieve(InstanceClass, "Folder", script, RunService:IsClient()):WaitForChild(InstanceName, math.huge)
76+
end
77+
78+
function Module:Get(InstanceClass: string, InstanceName: string): Instance
79+
local SetFolder = Retrieve(InstanceClass, "Folder", script, RunService:IsClient())
80+
local Item = SetFolder:FindFirstChild(InstanceName)
81+
82+
if Item then
83+
return Item
84+
elseif RunService:IsClient() then
85+
return SetFolder:WaitForChild(InstanceName)
86+
else
87+
return Retrieve(InstanceName, InstanceClass, SetFolder)
10288
end
103-
104-
function Module:LoadLibraryOnClient(...)
105-
if IsClient then
106-
return self:LoadLibrary(...)
89+
end
90+
91+
Module._BindToTag("oLibrary", function(Object)
92+
Libraries[Object.Name] = Object
93+
94+
for Thread, WantedName in next, LibraryThreadCache do
95+
if Object.Name == WantedName then
96+
LibraryThreadCache[Thread] = nil
97+
task.spawn(Thread, Object)
10798
end
10899
end
109-
110-
function Module:LoadLibraryOnServer(...)
111-
if IsServer then
112-
return self:LoadLibrary(...)
100+
end)
101+
102+
local function Initialize()
103+
if RunService:IsServer() then
104+
if script:GetAttribute("ServerHandled") then
105+
return
113106
end
107+
108+
script:SetAttribute("ServerHandled", true)
109+
110+
local oStarterPlayerScripts = Retrieve("StarterPlayerScripts", "Folder", script)
111+
local oStarterCharacterScripts = Retrieve("StarterCharacterScripts", "Folder", script)
112+
local function Reparent(Child, NewParent)
113+
if Child:IsA("LocalScript") and not Child.Disabled then
114+
Child:SetAttribute("EnableOnceReady", true)
115+
Child.Disabled = true
116+
end
117+
118+
Child.Parent = Retrieve(NewParent, "Folder", script)
119+
end
120+
121+
Module._BindToTag("oHandled", function(LuaSourceContainer: Instance)
122+
local RunsOn = LuaSourceContainer:GetAttribute("RunsOn") or "Empty"
123+
124+
if LuaSourceContainer:IsA("LocalScript") then
125+
if RunsOn == "Player" then
126+
task.defer(Reparent, LuaSourceContainer, "StarterPlayerScripts")
127+
elseif RunsOn == "Character" then
128+
task.defer(Reparent, LuaSourceContainer, "StarterCharacterScripts")
129+
else
130+
warn(string.format([[Unknown RunsOn type "%s" on %s]], RunsOn, LuaSourceContainer:GetFullName()))
131+
end
132+
elseif LuaSourceContainer:IsA("Script") then
133+
if RunsOn == "Player" then
134+
warn(string.format([[Invalid RunsOn type "%s" on %s]], RunsOn, LuaSourceContainer:GetFullName()))
135+
elseif RunsOn == "Character" then
136+
LuaSourceContainer.Parent = StarterCharacterScripts
137+
138+
for _, Player in next, PlayerService:GetPlayers() do
139+
if Player.Character then
140+
LuaSourceContainer:Clone().Parent = Player.Character
141+
end
142+
end
143+
else
144+
warn(string.format([[Unknown RunsOn type "%s" on %s]], RunsOn, LuaSourceContainer:GetFullName()))
145+
end
146+
elseif LuaSourceContainer:IsA("ModuleScript") then
147+
warn(string.format([[Invalid tag "oHandled" applied to %s]], LuaSourceContainer:GetFullName()))
148+
end
149+
end)
150+
151+
Module._BindToTag("oLibrary", function(LuaSourceContainer: Instance)
152+
if LuaSourceContainer:GetAttribute("ForceReplicate") then
153+
LuaSourceContainer.Parent = Retrieve("Libraries", "Folder", script)
154+
end
155+
end)
156+
157+
Module._BindToTag("ForceReplicate", function(LuaSourceContainer: Instance)
158+
LuaSourceContainer.Parent = Retrieve("Libraries", "Folder", script)
159+
end)
160+
161+
Module._BindToTag("StarterPlayerScripts", function(LuaSourceContainer: Instance)
162+
if LuaSourceContainer:IsA("LocalScript") then
163+
task.defer(Reparent, LuaSourceContainer, "StarterPlayerScripts")
164+
else
165+
warn(string.format([[Invalid tag "StarterPlayerScripts" applied to %s]], LuaSourceContainer:GetFullName()))
166+
end
167+
end)
168+
169+
Module._BindToTag("StarterCharacterScripts", function(LuaSourceContainer: Instance)
170+
if LuaSourceContainer:IsA("LocalScript") then
171+
task.defer(Reparent, LuaSourceContainer, "StarterCharacterScripts")
172+
elseif LuaSourceContainer:IsA("Script") then
173+
LuaSourceContainer.Parent = StarterCharacterScripts
174+
175+
for _, Player in next, PlayerService:GetPlayers() do
176+
if Player.Character then
177+
LuaSourceContainer:Clone().Parent = Player.Character
178+
end
179+
end
180+
else
181+
warn(string.format([[Invalid tag "StarterCharacterScripts" applied to %s]], LuaSourceContainer:GetFullName()))
182+
end
183+
end)
184+
elseif RunService:IsClient() then
185+
if script:GetAttribute("ClientHandled") then
186+
return
187+
end
188+
189+
script:SetAttribute("ClientHandled", true)
190+
191+
local Player = PlayerService.LocalPlayer
192+
local PlayerScripts = Player:WaitForChild("PlayerScripts")
193+
local oStarterPlayerScripts = script:WaitForChild("StarterPlayerScripts")
194+
local oStarterCharacterScripts = script:WaitForChild("StarterCharacterScripts")
195+
local function Reparent(Child, NewParent)
196+
Child.Parent = NewParent
197+
198+
if Child:IsA("LocalScript") and Child:GetAttribute("EnableOnceReady") then
199+
Child.Disabled = false
200+
end
201+
end
202+
203+
if script:FindFirstAncestorWhichIsA("PlayerGui") then
204+
task.defer(Reparent, script:Clone(), PlayerScripts)
205+
task.wait()
206+
207+
script.Disabled = true
208+
script:Destroy()
209+
210+
return
211+
end
212+
213+
Module._BindFunction(function(Child: Instance)
214+
task.defer(Reparent, Child, PlayerScripts)
215+
end, oStarterPlayerScripts.ChildAdded, oStarterPlayerScripts:GetChildren())
216+
217+
Module._BindFunction(function(Child: Instance)
218+
if Player.Character then
219+
task.defer(Reparent, Child:Clone(), Player.Character)
220+
end
221+
end, oStarterCharacterScripts.ChildAdded, oStarterCharacterScripts:GetChildren())
222+
223+
Module._BindFunction(function(Character: Instance)
224+
for _, Child in next, oStarterCharacterScripts:GetChildren() do
225+
task.spawn(Reparent, Child:Clone(), Character)
226+
end
227+
end, Player.CharacterAdded, {Player.Character})
114228
end
115229
end
116230

117-
for SetName, SetClass in next, RetrievalSets do
118-
local SetFolder = Retrieve(SetName, "Folder", ReplicatedStorage)
119-
120-
Module["GetLocal" .. SetName] = function(self, ItemName)
121-
return Retrieve(ItemName, SetClass, SetFolder)
122-
end
123-
124-
Module["WaitFor" .. SetName] = function(self, ItemName)
125-
return SetFolder:WaitForChild(ItemName, math.huge)
126-
end
127-
128-
Module["Get" .. SetName] = function(self, ItemName)
129-
local Item = SetFolder:FindFirstChild(ItemName)
130-
if Item then return Item end
131-
132-
if IsClient then
133-
return SetFolder:WaitForChild(ItemName)
134-
else
135-
return self["GetLocal" .. SetName](self, ItemName)
231+
do --/ LEGACY SUPPORT
232+
for _, SetClass in next, {"RemoteEvent", "RemoteFunction", "BindableEvent", "BindableFunction"} do
233+
local SetFolder = Retrieve(SetClass, "Folder", ReplicatedStorage)
234+
235+
Module["GetLocal" .. SetClass] = function(self, ItemName)
236+
return Retrieve(ItemName, SetClass, SetFolder)
237+
end
238+
239+
Module["WaitFor" .. SetClass] = function(self, ItemName)
240+
return SetFolder:WaitForChild(ItemName, math.huge)
241+
end
242+
243+
Module["Get" .. SetClass] = function(self, ItemName)
244+
local Item = SetFolder:FindFirstChild(ItemName)
245+
if Item then return Item end
246+
247+
if RunService:IsClient() then
248+
return SetFolder:WaitForChild(ItemName)
249+
else
250+
return self["GetLocal" .. SetClass](self, ItemName)
251+
end
136252
end
137253
end
138254
end
139255

140-
if not IsClient then
141-
BindToTag("StarterCharacterScripts", function(Object)
142-
Object.Parent = StarterPlayer.StarterCharacterScripts
143-
CollectionService:RemoveTag(Object, "StarterCharacterScripts")
144-
end)
145-
146-
BindToTag("StarterPlayerScripts", function(Object)
147-
Object.Parent = StarterPlayer.StarterPlayerScripts
148-
CollectionService:RemoveTag(Object, "StarterPlayerScripts")
149-
end)
150-
end
256+
--// Triggers
257+
258+
task.defer(Initialize)
151259

152260
return Module

0 commit comments

Comments
 (0)