Skip to content

Latest commit

 

History

History
133 lines (103 loc) · 4.42 KB

Resources_Plugin_Version.md

File metadata and controls

133 lines (103 loc) · 4.42 KB

This is an in-dev plugin version:

-- Plugin version of Resources
-- @author Validark

-- The plugin version will cache ALL ModuleScripts under TOP_OBJECT, even if they are within another ModuleScript
local TOP_OBJECT = script.Parent.Parent

local Resources = {}
local Caches = {} -- All cached data within Resources is accessible through Resources:GetLocalTable()

function Resources:GetLocalTable(TableName) -- Returns a cached table by TableName, generating if non-existant
	TableName = self ~= Resources and self or TableName
	local Table = Caches[TableName]

	if not Table then
		Table = {}
		Caches[TableName] = Table
	end

	return Table
end

local MakeGetterFunction do
	local Instance_new, type = Instance.new, type
	local InstantiableInstances = {Folder = true; RemoteEvent = true; BindableEvent = true; RemoteFunction = true; BindableFunction = true; Library = false}

	local function GetRootFolder()
		return script
	end

	function MakeGetterFunction(self, MethodName, Folder)
		if type(MethodName) ~= "string" then error("[Resources] Attempt to index Resources with invalid key: string expected, got " .. typeof(MethodName), 2) end

		local IsLocal, InstanceType, FolderGetter, FolderName, Instantiable, CacheName, Cache do -- Get Function Constants
			InstanceType, IsLocal = MethodName:gsub("^Get", "", 1)
			if IsLocal == 0 then error("[Resources] Methods should begin with \"Get\"", 2) end -- Make sure methods begin with "Get"

			InstanceType, IsLocal = InstanceType:gsub("^Local", "", 1) -- Remove "Get" and "Local" prefixes from MethodName to isolate InstanceType
			assert(IsLocal == 0, "[Resources] Plugin version of Resources should not use keyword `Local`")
			FolderGetter = InstanceType == "Folder" and GetRootFolder or Resources.GetFolder -- Determine whether Method is Local

			if InstanceType:byte(-1) == 121 then -- if last character is a 'y'
				local Last = InstanceType:byte(-2)
				FolderName = Last ~= 97 and Last ~= 101 and Last ~= 105 and Last ~= 111 and Last ~= 117 and InstanceType:sub(1, -2) .. "ies" or InstanceType .. "s"
			else
				FolderName = InstanceType .. "s" -- Set FolderName to ["RemoteEvent" .. "s"], or ["Librar" .. "ies"]
			end

			Instantiable = InstantiableInstances[InstanceType]
			CacheName = FolderName
			if Folder then
				Cache = Caches[CacheName]
			elseif Instantiable == nil then -- This block will never run for most people
				local GeneratedInstance
				Instantiable, GeneratedInstance = pcall(Instance_new, InstanceType)
				if Instantiable and GeneratedInstance then GeneratedInstance:Destroy() end
			end
		end

		local function GetFunction(this, InstanceName)
			InstanceName = this ~= self and this or InstanceName
			if type(InstanceName) ~= "string" then error("[Resources] " .. MethodName .. " expected a string parameter, got " .. typeof(InstanceName), 2) end

			if not Folder then
				Cache = Caches[CacheName]
				Folder = FolderGetter(FolderName)
				local Children = Folder:GetChildren() -- Cache children of Folder into Table

				if not Cache then
					Cache = Children -- Recycling is good!
					Caches[CacheName] = Children
				end

				for i = 1, #Children do
					local Child = Children[i]
					Cache[Child.Name] = Child
					Children[i] = nil
				end
			end

			local Object = Cache[InstanceName]

			if not Object then
				Object = Folder:FindFirstChild(InstanceName, true)

				if not Object then
					if not Instantiable then error("[Resources] " .. InstanceType .. " \"" .. InstanceName .. "\" is not installed within " .. Folder:GetFullName() .. ".", 2) end
					Object = Instance_new(InstanceType)
					Object.Name = InstanceName
					Object.Parent = Folder
				end

				Cache[InstanceName] = Object
			end

			return Object
		end

		Resources[MethodName] = GetFunction
		return GetFunction
	end

	local Libraries = Resources:GetLocalTable("Libraries")
	local Descendants = TOP_OBJECT:GetDescendants()

	for i = 1, #Descendants do
		local Library = Descendants[i]
		Libraries[Library.Name] = Library
	end

	MakeGetterFunction(Resources, "GetLibrary", TOP_OBJECT)
end

local LoadedLibraries = Resources:GetLocalTable("LoadedLibraries")

function Resources:LoadLibrary(LibraryName)
	LibraryName = self ~= Resources and self or LibraryName
	local Data = LoadedLibraries[LibraryName]

	if Data == nil then
		Data = require(Resources:GetLibrary(LibraryName))
		LoadedLibraries[LibraryName] = Data
	end

	return Data
end

return setmetatable(Resources, {
	__index = MakeGetterFunction;
	__call = Resources.LoadLibrary;
})