--[[ Requires modules to be loaded and adds them to a table
Required at runtime by server/client bootstrappers
]]
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
_G.MemTrack = {
Groups = {},
Add = function(self, groupName, object)
local group = self.Groups[groupName]
if not group then
group = {
Size = 0,
Objects = setmetatable({}, { __mode = "v" })
}
self.Groups[groupName] = group
end
group.Size += 1
group.Objects[group.Size] = object
return object
end,
CountObjectsAsync = function(self)
if not self.Counting then
task.spawn(function()
self.Counting = true
local result = {}
local nextYield = os.clock() + 0.2e-3
local function throttle()
if os.clock() >= nextYield then
task.wait()
nextYield = os.clock() + 0.2e-3
end
end
for groupName,group in pairs(self.Groups) do
for index = group.Size, 1, -1 do
if not group.Objects[index] then
group.Objects[index] = group.Objects[group.Size]
group.Objects[group.Size] = nil
group.Size -= 1
end
throttle()
end
result[groupName] = group.Size
throttle()
end
self.LastCount = result
self.Counting = false
end)
end
while self.Counting do
task.wait()
end
return self.LastCount
end,
}
local Global = {
IsClient = RunService:IsClient(),
IsServer = RunService:IsServer(),
RNG = Random.new()
}
local InitList = {}
--[[ Iterate through modules and initialize them and add to Global ]]
local IsServer = game:GetService("RunService"):IsServer()
local function loadModules(root)
for i,module in root:GetChildren() do
if module:IsA("Folder") then
loadModules(module)
end
if not module:IsA("ModuleScript") then
continue
end
local requiredModule = require(module)
if type(requiredModule) ~= "table" and type(requiredModule) ~= "function" then
continue
end
local skipLoad = module:GetAttribute("SkipLoad")
if not skipLoad then
InitList[module.Name] = requiredModule
end
if typeof(requiredModule) == "table" then
requiredModule._skipLoad = skipLoad
end
Global[module.Name] = requiredModule
end
end
function Global:TriggerInit()
for moduleName,module in InitList do
if type(module) ~= "table" then
continue
end
if module.Init and typeof(module.Init) == "function" then
module:Init()
end
end
--[[ Start ensures safety(other modules are initialized at this point)]]
for moduleName,module in InitList do
if type(module) ~= "table" then
continue
end
if moduleName == "ClientPlayerData" then
continue -- We start this manually in the loading gate
end
if module.Start and typeof(module.Start) == "function" then
module:Start()
end
end
self:AfterStart()
end
function Global:AfterStart()
for i,module in Global do
if typeof(module) ~= "table" then
continue
end
if module._skipLoad then
continue
end
--[[ Module updates ]]
for i,tab in module do
if typeof(tab) ~= "table" then
continue
end
local label = tab.UpdateLabel
if label and tab.fn then
local fn = tab.fn
Global:BindToHeartbeat(label,tab.Priority or Global.EventPriority.Default,function(dt)
fn(module,dt)
end)
end
end
--
end
end
task.defer(function()
print("Loading modules...")
loadModules(ReplicatedStorage.SharedModules)
--[[ Some commonly used things ]]
Global.FrameDelta = Global.Mathf.FrameDelta
Global.FrameDeltaAlpha = function(n,dt)
return math.clamp(Global.FrameDelta((1/60) / n,dt),0,1)
end
--
if IsServer then
loadModules(game.ServerStorage.ServerModules)
else
Global.Mouse = Players.LocalPlayer:GetMouse()
Global.Player = Players.LocalPlayer
loadModules(ReplicatedStorage.ClientModules)
end
loadModules(game.ReplicatedFirst.Modules)
--
print("Modules loaded")
--[[ Init sharedvalues ]]
if Global.IsServer then
Global.SharedValues = {}
else
Global.SharedValues = Global.Network:InvokeServer("GetSharedValues")
end
if Global.IsServer then
local sharedValues = Global.SharedValues
Global.Network:BindFunctions({
GetSharedValues = function(player)
if player:GetAttribute("GotSharedValues") then
return
end
player:SetAttribute("GotSharedValues", true)
return sharedValues
end,
})
end
--
for i,v in pairs(Global.GameEvents) do
Global[i] = v
end
if RunService:IsServer() then
Global:TriggerInit()
end
Global.IsLoaded = true
end)
return Global