local r={Services={},Modules={};Shared={}}local D={__index=r}local Z=(game:GetService("\083\101\114\118\101\114\083\116\111\114\097\103\101")).Aero.Services local C=(game:GetService("\083\101\114\118\101\114\083\116\111\114\097\103\101")).Aero.Modules local L=(game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")).Aero.Shared local B=(game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")).Aero.Internal local g=Instance.new("\070\111\108\100\101\114")g.Name="\065\101\114\111\082\101\109\111\116\101\083\101\114\118\105\099\101\115"local w=require(B.FastSpawn)local function W()error("\067\097\110\110\111\116 \114\101\103\105\115\116\101\114 \101\118\101\110\116 \097\102\116\101\114 \073\110\105\116 \109\101\116\104\111\100")end local function m()error("\067\097\110\110\111\116 \114\101\103\105\115\116\101\114 \102\117\110\099\116\105\111\110 \097\102\116\101\114 \073\110\105\116 \109\101\116\104\111\100")end function r.RegisterEvent(D,r)local Z=D.Shared.Event.new()D._events[r]=Z return Z end function r.RegisterClientEvent(D,r)local Z=Instance.new("\082\101\109\111\116\101\069\118\101\110\116")Z.Name=r Z.Parent=D._remoteFolder D._clientEvents[r]=Z return Z end function r.FireEvent(D,r,...)D._events[r]:Fire(...)end function r.FireClientEvent(Z,r,D,...)Z._clientEvents[r]:FireClient(D,...)end function r.FireAllClientsEvent(D,r,...)D._clientEvents[r]:FireAllClients(...)end function r.ConnectEvent(Z,r,D)return Z._events[r]:Connect(D)end function r.ConnectClientEvent(Z,r,D)return Z._clientEvents[r].OnServerEvent:Connect(D)end function r.WaitForEvent(D,r)return D._events[r]:Wait()end function r.WaitForClientEvent(D,r)return D._clientEvents[r]:Wait()end function r.RegisterClientFunction(Z,r,D)local C=Instance.new("\082\101\109\111\116\101\070\117\110\099\116\105\111\110")C.Name=r C.OnServerInvoke=function(...)return D(Z.Client,...)end C.Parent=Z._remoteFolder return C end function r.WrapModule(Z,r)assert(type(r)=="\116\097\098\108\101","\069\120\112\101\099\116\101\100 \116\097\098\108\101 \102\111\114 \097\114\103\117\109\101\110\116")r._events={}setmetatable(r,D)if type(r.Init)=="\102\117\110\099\116\105\111\110"and not r.__aeroPreventInit then r:Init()end if type(r.Start)=="\102\117\110\099\116\105\111\110"and not r.__aeroPreventStart then w(r.Start,r)end end local function M(D,Z)setmetatable(D,{__index=function(D,C)local L=Z[C]if L:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then local Z=require(L)if type(Z)=="\116\097\098\108\101"then r:WrapModule(Z)end rawset(D,C,Z)return Z elseif L:IsA("\070\111\108\100\101\114")then local r={}rawset(D,C,r)M(r,L)return r end end})end local function Q(r,Z,C)local L=Instance.new("\070\111\108\100\101\114")L.Name=r.Name L.Parent=C local B=require(r)Z[r.Name]=B if type(B.Client)~="\116\097\098\108\101"then B.Client={}end B.Client.Server=B setmetatable(B,D)B._events={}B._clientEvents={}B._remoteFolder=L end local function F(r)if type(r.Init)=="\102\117\110\099\116\105\111\110"then r:Init()end for D,Z in pairs(r.Client)do if type(Z)=="\102\117\110\099\116\105\111\110"then r:RegisterClientFunction(D,Z)end end r.RegisterEvent=W r.RegisterClientEvent=W r.RegisterClientFunction=m end local function E(r)if type(r.Start)=="\102\117\110\099\116\105\111\110"then w(r.Start,r)end end local function z(B)local function w(r,D,Z)if B then print("\076\111\097\100 \115\101\114\118\105\099\101 \109\111\100\117\108\101\115")end for r,C in pairs(r:GetChildren())do if C:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then Q(C,D,Z)elseif C:IsA("\070\111\108\100\101\114")then local r={}local L=Instance.new("\070\111\108\100\101\114")L.Name=C.Name L.Parent=Z D[C.Name]=r w(C,r,L)end end end local function W(r)if B then print("\073\110\105\116\105\097\108\105\122\101 \115\101\114\118\105\099\101\115")end for r,Z in pairs(r)do if getmetatable(Z)==D then F(Z)else W(Z)end end end local function m(r)for r,D in pairs(r:GetChildren())do if D:IsA("\070\111\108\100\101\114")then local r=D:FindFirstChildWhichIsA("\082\101\109\111\116\101\070\117\110\099\116\105\111\110",true)local Z=D:FindFirstChildWhichIsA("\082\101\109\111\116\101\069\118\101\110\116",true)if not r and not Z then D:Destroy()else m(D)end end end end local function z(r)for r,Z in pairs(r)do if getmetatable(Z)==D then E(Z)else z(Z)end end end M(r.Modules,C)M(r.Shared,L)w(Z,r.Services,g)W(r.Services)m(g)z(r.Services)g.Parent=(game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")).Aero _G.AeroServer=r end z()
-- Aero Server
-- Crazyman32
-- July 21, 2017



local AeroServer = {
	Services = {};
	Modules = {};
	Shared = {};
}

local mt = {__index = AeroServer}

local servicesFolder = game:GetService("ServerStorage").Aero.Services
local modulesFolder = game:GetService("ServerStorage").Aero.Modules
local sharedFolder = game:GetService("ReplicatedStorage").Aero.Shared
local internalFolder = game:GetService("ReplicatedStorage").Aero.Internal

local remoteServices = Instance.new("Folder")
remoteServices.Name = "AeroRemoteServices"

local FastSpawn = require(internalFolder.FastSpawn)

local function PreventEventRegister()
	error("Cannot register event after Init method")
end

local function PreventFunctionRegister()
	error("Cannot register function after Init method")
end


function AeroServer:RegisterEvent(eventName)
	local event = self.Shared.Event.new()
	self._events[eventName] = event
	return event
end


function AeroServer:RegisterClientEvent(eventName)
	local event = Instance.new("RemoteEvent")
	event.Name = eventName
	event.Parent = self._remoteFolder
	self._clientEvents[eventName] = event
	return event
end


function AeroServer:FireEvent(eventName, ...)
	self._events[eventName]:Fire(...)
end


function AeroServer:FireClientEvent(eventName, client, ...)
	self._clientEvents[eventName]:FireClient(client, ...)
end


function AeroServer:FireAllClientsEvent(eventName, ...)
	self._clientEvents[eventName]:FireAllClients(...)
end


function AeroServer:ConnectEvent(eventName, func)
	return self._events[eventName]:Connect(func)
end


function AeroServer:ConnectClientEvent(eventName, func)
	return self._clientEvents[eventName].OnServerEvent:Connect(func)
end


function AeroServer:WaitForEvent(eventName)
	return self._events[eventName]:Wait()
end


function AeroServer:WaitForClientEvent(eventName)
	return self._clientEvents[eventName]:Wait()
end


function AeroServer:RegisterClientFunction(funcName, func)
	local remoteFunc = Instance.new("RemoteFunction")
	remoteFunc.Name = funcName
	remoteFunc.OnServerInvoke = function(...)
		return func(self.Client, ...)
	end
	remoteFunc.Parent = self._remoteFolder
	return remoteFunc
end


function AeroServer:WrapModule(tbl)
	assert(type(tbl) == "table", "Expected table for argument")
	tbl._events = {}
	setmetatable(tbl, mt)
	if (type(tbl.Init) == "function" and not tbl.__aeroPreventInit) then
		tbl:Init()
	end
	if (type(tbl.Start) == "function" and not tbl.__aeroPreventStart) then
		FastSpawn(tbl.Start, tbl)
	end
end


-- Setup table to load modules on demand:
local function LazyLoadSetup(tbl, folder)
	setmetatable(tbl, {
		__index = function(t, i)
			local child = folder[i]
			if (child:IsA("ModuleScript")) then
				local obj = require(child)
				if (type(obj) == "table") then
					AeroServer:WrapModule(obj)
				end
				rawset(t, i, obj)
				return obj
			elseif (child:IsA("Folder")) then
				local nestedTbl = {}
				rawset(t, i, nestedTbl)
				LazyLoadSetup(nestedTbl, child)
				return nestedTbl
			end
		end;
	})
end


-- Load service from module:
local function LoadService(module, servicesTbl, parentFolder)
	
	local remoteFolder = Instance.new("Folder")
	remoteFolder.Name = module.Name
	remoteFolder.Parent = parentFolder
	
	local service = require(module)
	servicesTbl[module.Name] = service
	
	if (type(service.Client) ~= "table") then
		service.Client = {}
	end
	service.Client.Server = service
	
	setmetatable(service, mt)
	
	service._events = {}
	service._clientEvents = {}
	service._remoteFolder = remoteFolder
	
end


local function InitService(service)
	
	-- Initialize:
	if (type(service.Init) == "function") then
		service:Init()
	end
	
	-- Client functions:
	for funcName,func in pairs(service.Client) do
		if (type(func) == "function") then
			service:RegisterClientFunction(funcName, func)
		end
	end

	-- Disallow registering events/functions after init:
	service.RegisterEvent = PreventEventRegister
	service.RegisterClientEvent = PreventEventRegister
	service.RegisterClientFunction = PreventFunctionRegister
	
end


local function StartService(service)

	-- Start services on separate threads:
	if (type(service.Start) == "function") then
		FastSpawn(service.Start, service)
	end

end


local function Init(logProgress)
	
	-- Load service modules:
	local function LoadAllServices(parent, servicesTbl, parentFolder)
		if logProgress then
			print("Load service modules")
		end
		for _,child in pairs(parent:GetChildren()) do
			if (child:IsA("ModuleScript")) then
				LoadService(child, servicesTbl, parentFolder)
			elseif (child:IsA("Folder")) then
				local tbl = {}
				local folder = Instance.new("Folder")
				folder.Name = child.Name
				folder.Parent = parentFolder
				servicesTbl[child.Name] = tbl
				LoadAllServices(child, tbl, folder)
			end
		end
	end
	
	-- Initialize services:
	local function InitAllServices(services)
		if logProgress then
			print("Initialize services")
		end
		for _,service in pairs(services) do
			if (getmetatable(service) == mt) then
				InitService(service)
			else
				InitAllServices(service)
			end
		end
	end

	-- Remove unused folders:
	local function ScanRemoteFoldersForEmpty(parent)
		for _,child in pairs(parent:GetChildren()) do
			if (child:IsA("Folder")) then
				local remoteFunction = child:FindFirstChildWhichIsA("RemoteFunction", true)
				local remoteEvent = child:FindFirstChildWhichIsA("RemoteEvent", true)
				if ((not remoteFunction) and (not remoteEvent)) then
					child:Destroy()
				else
					ScanRemoteFoldersForEmpty(child)
				end
			end
		end
	end
	
	-- Start services:
	local function StartAllServices(services)
		for _,service in pairs(services) do
			if (getmetatable(service) == mt) then
				StartService(service)
			else
				StartAllServices(service)
			end
		end
	end

	--------------------------------------------------------------------
	
	-- Lazy-load server and shared modules:
	LazyLoadSetup(AeroServer.Modules, modulesFolder)
	LazyLoadSetup(AeroServer.Shared, sharedFolder)

	-- Load, init, and start services:
	LoadAllServices(servicesFolder, AeroServer.Services, remoteServices)
	InitAllServices(AeroServer.Services)
	ScanRemoteFoldersForEmpty(remoteServices)
	StartAllServices(AeroServer.Services)
	
	-- Expose server framework to client and global scope:
	remoteServices.Parent = game:GetService("ReplicatedStorage").Aero
	_G.AeroServer = AeroServer
	
end


Init()