local I=5 local y=require((script:WaitForChild("\078\101\120\117\115\073\110\115\116\097\110\099\101")):WaitForChild("\078\101\120\117\115\079\098\106\101\099\116"))local g=require(script:WaitForChild("\078\101\120\117\115\080\114\111\106\101\099\116\067\111\110\116\101\120\116"))local n=y:Extend()n:SetClassName("\078\101\120\117\115\080\114\111\106\101\099\116")function n.__new(g,I,y)g:InitializeSuper()g.__BaseReference=I g.__SuppressCyclicWarnings=y==true g.__Links={}g.__CachedResources={}g.__LoadingResources={}g.__InternalDependencies={}g.__ExternalDependencies={}end function n.__AddInternalDependency(g,I,y)if not g.__InternalDependencies[I]then g.__InternalDependencies[I]={}end local n=g.__InternalDependencies[I]for I,g in pairs(n)do if g==y then return end end table.insert(n,y)end function n.__AddExternalDependency(g,I,y)if not g.__ExternalDependencies[I]then g.__ExternalDependencies[I]={}end local n=g.__ExternalDependencies[I]for I,g in pairs(n)do if g==y then return end end table.insert(n,y)end function n.__AddDependency(g,I,y)if g:IsInstanceInPath(I)then g:__AddInternalDependency(g:GetPathFromInstance(I),y)else g:__AddExternalDependency(I,y)end end function n.IsLoading(y,I)return y.__LoadingResources[I]==true end function n.IsInstanceInPath(y,I)if I==y.__BaseReference or y.__BaseReference:IsAncestorOf(I)then return true end for y,g in pairs(y.__Links)do if I==g or g:IsAncestorOf(I)then return true end end return false end function n.IsResourceCyclic(y,I)return y:GetDependencyPath(I,I)~=nil end function n.GetObjectReference(y,I)local g=string.split(I,"\046")if I==""then g={}end local n=y.__BaseReference for I,y in pairs(y.__Links)do if g[1]==I then table.remove(g,1)n=y break end end local b=n for I,y in pairs(g)do if b==nil then break end b=b:WaitForChild(y)end return b end function n.GetPathFromInstance(y,I)local g=""local n=I while n~=nil do local I=false if n==y.__BaseReference then break end for y,b in pairs(y.__Links)do if b==n then g=y..("\046"..g)I=true break end end if I then break end g=n.Name..("\046"..g)n=n.Parent end if n==nil then error("\073\110\115\116\097\110\099\101 \105\115\110\'\116 \112\097\114\116 \111\102 \116\104\101 \112\114\111\106\101\099\116\058 "..tostring(I:GetFullName()))end return string.sub(g,1,#g-1)end function n.GetDependencyPath(n,I,y,g)g=g or{}g[I]=true local b=n.__InternalDependencies[I]if not b then return nil end for g,n in pairs(b)do if y==n then return{I;y}end end for b,G in pairs(b)do if not g[G]then local b=n:GetDependencyPath(G,y,g)if b then table.insert(b,1,I)return b end end end return nil end function n.GetContext(y,I)return g.new(I,y)end function n.GetResource(g,y)local n=g.__CachedResources[y]if n then return n end g.__LoadingResources[y]=true;(coroutine.wrap(function()local I=g:GetObjectReference(y)if typeof(I)=="\073\110\115\116\097\110\099\101"and(I.IsA and I:IsA("\077\111\100\117\108\101\083\099\114\105\112\116"))then I=require(I)end if not g.__CachedResources[y]then g.__CachedResources[y]=I end g.__LoadingResources[y]=nil end))()local b=tick()local G=false local z while z==nil and g.__LoadingResources[y]do z=g.__CachedResources[y]if z~=nil then return z end if G==false and(g.__SuppressCyclicWarnings~=true and tick()-b>I)then local I=g:GetDependencyPath(y,y)if I then G=true warn("\065 \100\101\112\101\110\100\101\110\099\121 \108\111\111\112 \101\120\105\115\116\115\058")for I,y in pairs(I)do warn("\t"..y)end warn("\085\115\101 \078\101\120\117\115\080\114\111\106\101\099\116\058\058\083\101\116\082\101\115\111\117\114\099\101 \111\114 \078\101\120\117\115\080\114\111\106\101\099\116\067\111\110\116\101\120\116\058\058\083\101\116\067\111\110\116\101\120\116\082\101\115\111\117\114\099\101 \116\111 \097\108\108\111\119 \116\104\101 \108\111\111\112 \116\111 \101\110\100 \119\105\116\104\111\117\116 \104\097\118\105\110\103 \116\111 \108\111\097\100 \116\104\101 \114\101\115\111\117\114\099\101\115\046")end end wait()end return g.__CachedResources[y]end function n.CreatePathLink(g,I,y)g.__Links[I]=y end function n.SetResource(g,I,y)g.__CachedResources[I]=y end return n
--[[
TheNexusAvenger

Simplifies manages resources in large scale projects.
--]]

local CYCLIC_WARNING_TIME_REQUIREMENT = 5



local NexusObject = require(script:WaitForChild("NexusInstance"):WaitForChild("NexusObject"))
local NexusProjectContext = require(script:WaitForChild("NexusProjectContext"))

local NexusProject = NexusObject:Extend()
NexusProject:SetClassName("NexusProject")



--[[
Creates an instance of Nexus Project.
--]]
function NexusProject:__new(ReferenceInstance,SuppressCyclicWarnings)
	self:InitializeSuper()
	self.__BaseReference = ReferenceInstance
	self.__SuppressCyclicWarnings = SuppressCyclicWarnings == true
	
	self.__Links = {}
	self.__CachedResources = {}
	self.__LoadingResources = {}
	self.__InternalDependencies = {}
	self.__ExternalDependencies = {}
end

--[[
Adds an internal dependency reference.
--]]
function NexusProject:__AddInternalDependency(DependentPath,DependencyPath)
	--Add the table if it doesn't exist.
	if not self.__InternalDependencies[DependentPath] then
		self.__InternalDependencies[DependentPath] = {}
	end
	
	--Return if the reference exists.
	local Dependencies = self.__InternalDependencies[DependentPath]
	for _,Dependency in pairs(Dependencies) do
		if Dependency == DependencyPath then
			return
		end
	end
	
	--Add the dependency.
	table.insert(Dependencies,DependencyPath)
end

--[[
Adds an external dependency reference.
--]]
function NexusProject:__AddExternalDependency(DependentInstance,DependencyPath)
	--Add the table if it doesn't exist.
	if not self.__ExternalDependencies[DependentInstance] then
		self.__ExternalDependencies[DependentInstance] = {}
	end
	
	--Return if the reference exists.
	local Dependencies = self.__ExternalDependencies[DependentInstance]
	for _,Dependency in pairs(Dependencies) do
		if Dependency == DependencyPath then
			return
		end
	end
	
	--Add the dependency.
	table.insert(Dependencies,DependencyPath)
end

--[[
Adds a dependency reference.
--]]
function NexusProject:__AddDependency(DependentInstance,DependencyPath)
	if self:IsInstanceInPath(DependentInstance) then
		self:__AddInternalDependency(self:GetPathFromInstance(DependentInstance),DependencyPath)
	else
		self:__AddExternalDependency(DependentInstance,DependencyPath)
	end
end

--[[
Returns if a resource loading.
--]]
function NexusProject:IsLoading(Path)
	return self.__LoadingResources[Path] == true
end

--[[
Returns if an instance is part of the project.
--]]
function NexusProject:IsInstanceInPath(Ins)
	--Return true if it is or is under the base reference.
	if Ins == self.__BaseReference or self.__BaseReference:IsAncestorOf(Ins) then
		return true
	end
	
	--Return true if it is equal to or under a linked reference.
	for _,Reference in pairs(self.__Links) do
		if Ins == Reference or Reference:IsAncestorOf(Ins) then
			return true
		end
	end
	
	--Return false (not part of the project).
	return false
end

--[[
Returns if a dependent eventually has itself
as a dependent.
--]]
function NexusProject:IsResourceCyclic(Path)
	return self:GetDependencyPath(Path,Path) ~= nil
end

--[[
Returns the object reference for the given string.
--]]
function NexusProject:GetObjectReference(Path)
	--Split the path.
	local SplitPath = string.split(Path,".")
	if Path == "" then
		SplitPath = {}
	end
	
	--Get the base instance.
	local Base = self.__BaseReference
	for FirstItem,Reference in pairs(self.__Links) do
		if SplitPath[1] == FirstItem then
			table.remove(SplitPath,1)
			Base = Reference
			break
		end
	end
	
	--Get the reference.
	local Reference = Base
	for _,PathPart in pairs(SplitPath) do
		if Reference == nil then
			break
		end
		
		Reference = Reference:WaitForChild(PathPart)
	end
	
	--Retrun the reference.
	return Reference
end

--[[
Returns the project path for the given instance. Throws
an error if the instance isn't part of the project.
--]]
function NexusProject:GetPathFromInstance(Ins)
	local Path = ""
	local CurrentReference = Ins
	
	--Move up the path until nil is reached.
	while CurrentReference ~= nil do
		--Break the loop if the root of the project was reached.
		local ParentReached = false
		if CurrentReference == self.__BaseReference then
			break
		end
		for PathPart,Reference in pairs(self.__Links) do
			if Reference == CurrentReference then
				Path = PathPart.."."..Path
				ParentReached = true
				break
			end
		end
		if ParentReached then break end
		
		--Add to the path and move up.
		Path = CurrentReference.Name.."."..Path
		CurrentReference = CurrentReference.Parent
	end
	
	--If the current reference is nil, throw an error.
	if CurrentReference == nil then
		error("Instance isn't part of the project: "..tostring(Ins:GetFullName()))
	end
	
	--Return the path.
	return string.sub(Path,1,#Path - 1)
end

--[[
Returns a table of the path from a dependent to a sub-dependent.
Returns nil if the dependent doesn't have the dependency.
--]]
function NexusProject:GetDependencyPath(Dependent,Dependency,VisitiedDependents)
	VisitiedDependents = VisitiedDependents or {}
	VisitiedDependents[Dependent] = true
	local Dependencies = self.__InternalDependencies[Dependent]
	
	--Return nil if dependencies don't exists.
	if not Dependencies then
		return nil
	end
	
	--Return if the dependent has the given dependency.
	for _,OtherDependency in pairs(Dependencies) do
		if Dependency == OtherDependency then
			return {Dependent,Dependency}
		end
	end
	
	--Return if a dependency has the given dependency.
	for _,OtherDependency in pairs(Dependencies) do
		if not VisitiedDependents[OtherDependency] then
			local DependencyList =  self:GetDependencyPath(OtherDependency,Dependency,VisitiedDependents)
			if DependencyList then
				table.insert(DependencyList,1,Dependent)
				return DependencyList
			end
		end
	end
	
	--Return nil (not a dependency).
	return nil
end

--[[
Returns a context for getting resources. The first
parameter should be the "script" property. This is
used for detecting and warning cyclic dependencies
(A requires B, B requires A).
--]]
function NexusProject:GetContext(ScriptReference)
	return NexusProjectContext.new(ScriptReference,self)
end

--[[
Returns the resource for the given path. If it is a
ModuleScript, it is required and returned.
--]]
function NexusProject:GetResource(Path)
	--Return a cached resource if it exists.
	local CachedResource = self.__CachedResources[Path]
	if CachedResource then
		return CachedResource
	end
	
	--Get the resource and require it if it is a ModuleScript.
	self.__LoadingResources[Path] = true
	coroutine.wrap(function()
		local Resource = self:GetObjectReference(Path)
		if typeof(Resource) == "Instance" and Resource.IsA and Resource:IsA("ModuleScript") then
			Resource = require(Resource)
		end
		
		--Cache the resource.
		if not self.__CachedResources[Path] then
			self.__CachedResources[Path] = Resource
		end
		
		--Register the resource as loaded.
		self.__LoadingResources[Path] = nil
	end)()
	
	--Start a loop and wait for the instance.
	local StartTime = tick()
	local WarningDisplayed = false
	local Resource
	while Resource == nil and self.__LoadingResources[Path] do
		Resource = self.__CachedResources[Path]
		
		--Break if the resource exists.
		if Resource ~= nil then
			return Resource
		end
	
		--Display a warning if it is cyclic.
		if WarningDisplayed == false and self.__SuppressCyclicWarnings ~= true and tick() - StartTime > CYCLIC_WARNING_TIME_REQUIREMENT then
			local DependencyPath = self:GetDependencyPath(Path,Path)
			if DependencyPath then
				WarningDisplayed = true
				warn("A dependency loop exists:")
				for _,Path in pairs(DependencyPath) do
					warn("\t"..Path)
				end 
				warn("Use NexusProject::SetResource or NexusProjectContext::SetContextResource to allow the loop to end without having to load the resources.")
			end
		end
		wait()
	end
	
	--Return the resource.
	return self.__CachedResources[Path]
end

--[[
Creates a link between a string and a game
reference. Note that it will only be valid for the
first word (ex: "game" in "game.Workspace") and
the given string should NOT have a period. Also
note that links are case sensitive.
--]]
function NexusProject:CreatePathLink(Reference,Object)
	self.__Links[Reference] = Object
end

--[[
Registers a resource with a given path. If GetResource
is called, it will use what is registered.
--]]
function NexusProject:SetResource(Path,Resource)
	self.__CachedResources[Path] = Resource
end



return NexusProject