local l=game:GetService("\082\117\110\083\101\114\118\105\099\101")local s=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local b=game:GetService("\083\101\114\118\101\114\083\099\114\105\112\116\083\101\114\118\105\099\101")local p=require(script.Parent.LoaderUtils)local W=require(script.Parent.BounceTemplateUtils)local R=require(script.Parent.Loader)local A={}A.ClassName="\076\101\103\097\099\121\076\111\097\100\101\114"A.__index=A function A.new(l)return setmetatable({_script=assert(l,"\078\111 \115\099\114\105\112\116"),_container=false,_locked=false,_lookupMap={}},A)end function A.Lock(l)assert(not l._container,"\067\097\110\110\111\116 \098\111\111\116\115\116\114\097\112 \103\097\109\101 \119\104\101\110 \108\101\103\097\099\121 \108\111\097\100\101\114 \119\097\115 \097\108\114\101\097\100\121 \117\115\101\100")l._locked=true end function A.GetLoader(s,l)return R.new(l)end function A.Require(s,l)assert(not s._locked,"\067\097\110\110\111\116 \117\115\101 \108\101\103\097\099\121 \108\111\097\100\101\114 \097\102\116\101\114 \097\108\114\101\097\100\121 \116\114\097\110\115\102\111\114\109\101\100")s:_setupIfNeeded()if type(l)=="\110\117\109\098\101\114"then return require(l)elseif type(l)=="\115\116\114\105\110\103"then local b=s._lookupMap[l]if b then return require(b)else error("\069\114\114\111\114\058 \076\105\098\114\097\114\121 \'"..(tostring(l).."\' \100\111\101\115 \110\111\116 \101\120\105\115\116\046"),2)end elseif typeof(l)=="\073\110\115\116\097\110\099\101"and l:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then return require(l)else error(("\069\114\114\111\114\058 \109\111\100\117\108\101 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103 \111\114 \077\111\100\117\108\101\083\099\114\105\112\116\044 \103\111\116 \'\037\115\' \102\111\114 \'\037\115\'"):format(typeof(l),tostring(l)))end end function A._buildLookupContainer(l)for s,b in pairs(l._container:GetDescendants())do if b:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")and not b:FindFirstAncestorWhichIsA("\077\111\100\117\108\101\083\099\114\105\112\116")then local s=b if W.isBounceTemplate(b)then s=W.getTarget(b)or b end local p=l._lookupMap[b.Name]if p then if s~=p then warn(("\091\076\101\103\097\099\121\076\111\097\100\101\114\093 - \068\117\112\108\105\099\097\116\101 \109\111\100\117\108\101 \037\113 \102\111\117\110\100\044 \117\115\105\110\103 \102\105\114\115\116 \102\111\117\110\100\n\t\040\049\041 \037\115 \040\117\115\101\100\041\n\t\040\050\041 \037\115"):format(b.Name,l._lookupMap[b.Name]:GetFullName(),b:GetFullName()))end else l._lookupMap[b.Name]=s end end end end function A._setupIfNeeded(W)local R=rawget(W,"\095\099\111\110\116\097\105\110\101\114")if R then return R end assert(W._script.Name=="\078\101\118\101\114\109\111\114\101","\067\097\110\110\111\116 \105\110\118\111\107\101 \108\101\103\097\099\121 \109\111\100\101 \105\102 \110\111\116 \097\116 \082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101\046\078\101\118\101\114\109\111\114\101")assert(W._script.Parent==s,"\067\097\110\110\111\116 \105\110\118\111\107\101 \108\101\103\097\099\121 \109\111\100\101 \105\102 \110\111\116 \097\116 \082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101\046\078\101\118\101\114\109\111\114\101")if not l:IsRunning()then error("\084\101\115\116 \109\111\100\101 \110\111\116 \115\117\112\112\111\114\116\101\100")elseif l:IsServer()and l:IsClient()or not l:IsRunning()then if l:IsRunning()then error("\087\097\114\110\105\110\103\058 \076\111\097\100\105\110\103 \097\108\108 \109\111\100\117\108\101\115 \105\110 \080\108\097\121\083\111\108\111\046 \073\116\'\115 \114\101\099\111\109\109\101\110\100\101\100 \121\111\117 \117\115\101 \097\099\099\117\114\097\116\101 \112\108\097\121 \115\111\108\111\046")end elseif l:IsServer()then local l=b:FindFirstChild("\078\101\118\101\114\109\111\114\101")or error("\078\111 \083\101\114\118\101\114\083\099\114\105\112\116\083\101\114\118\105\099\101\046\078\101\118\101\114\109\111\114\101 \102\111\108\100\101\114")local R,A,C=p.toWallyFormat(l)R.Name="\095\110\101\118\101\114\109\111\114\101\067\108\105\101\110\116"R.Parent=s C.Name="\095\110\101\118\101\114\109\111\114\101\083\104\097\114\101\100"C.Parent=s A.Name="\095\110\101\118\101\114\109\111\114\101\083\101\114\118\101\114"A.Parent=b rawset(W,"\095\099\111\110\116\097\105\110\101\114",A)W:_buildLookupContainer()elseif l:IsClient()then local l=s:WaitForChild("\095\110\101\118\101\114\109\111\114\101\067\108\105\101\110\116",2)if not l then warn("\091\078\101\118\101\114\109\111\114\101\093 - \066\101 \115\117\114\101 \116\111 \099\097\108\108 \114\101\113\117\105\114\101\040\083\101\114\118\101\114\083\099\114\105\112\116\083\101\114\118\105\099\101\046\078\101\118\101\114\109\111\114\101\041 \111\110 \116\104\101 \115\101\114\118\101\114 \116\111 \114\101\112\108\105\099\097\116\101 \110\101\118\101\114\109\111\114\101")l=s:WaitForChild("\095\110\101\118\101\114\109\111\114\101\067\108\105\101\110\116")end rawset(W,"\095\099\111\110\116\097\105\110\101\114",l)W:_buildLookupContainer()else error("\069\114\114\111\114\058 \085\110\107\110\111\119\110 \082\117\110\083\101\114\118\105\099\101 \115\116\097\116\101 \040\078\111\116 \099\108\105\101\110\116\047\115\101\114\118\101\114\047\116\101\115\116 \109\111\100\101\041")end end return A


local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")

local LoaderUtils = require(script.Parent.LoaderUtils)
local BounceTemplateUtils = require(script.Parent.BounceTemplateUtils)
local Loader = require(script.Parent.Loader)

local LegacyLoader = {}
LegacyLoader.ClassName = "LegacyLoader"
LegacyLoader.__index = LegacyLoader

function LegacyLoader.new(script)
	return setmetatable({
		_script = assert(script, "No script");
		_container = false;
		_locked = false;
		_lookupMap = {};
	}, LegacyLoader)
end

function LegacyLoader:Lock()
	assert(not self._container, "Cannot bootstrap game when legacy loader was already used")
	self._locked = true
end

function LegacyLoader:GetLoader(moduleScript)
	return Loader.new(moduleScript)
end

function LegacyLoader:Require(value)
	assert(not self._locked, "Cannot use legacy loader after already transformed")

	self:_setupIfNeeded()

	if type(value) == "number" then
		return require(value)
	elseif type(value) == "string" then
		local existing = self._lookupMap[value]
		if existing then
			return require(existing)
		else
			error("Error: Library '" .. tostring(value) .. "' does not exist.", 2)
		end
	elseif typeof(value) == "Instance" and value:IsA("ModuleScript") then
		return require(value)
	else
		error(("Error: module must be a string or ModuleScript, got '%s' for '%s'")
			:format(typeof(value), tostring(value)))
	end
end

function LegacyLoader:_buildLookupContainer()
	for _, instance in pairs(self._container:GetDescendants()) do
		if instance:IsA("ModuleScript")
			and not instance:FindFirstAncestorWhichIsA("ModuleScript") then
			local target = instance
			if BounceTemplateUtils.isBounceTemplate(instance) then
				target = BounceTemplateUtils.getTarget(instance) or instance
			end

			local existing = self._lookupMap[instance.Name]
			if existing then
				if target ~= existing then
					warn(("[LegacyLoader] - Duplicate module %q found, using first found\n\t(1) %s (used)\n\t(2) %s")
						:format(
							instance.Name,
							self._lookupMap[instance.Name]:GetFullName(),
							instance:GetFullName()))
				end
			else
				self._lookupMap[instance.Name] = target
			end
		end
	end
end

function LegacyLoader:_setupIfNeeded()
	local existingContainer = rawget(self, "_container")
	if existingContainer then
		return existingContainer
	end

	-- TODO: Handle setup by manual process
	assert(self._script.Name == "Nevermore", "Cannot invoke legacy mode if not at ReplicatedStorage.Nevermore")
	assert(self._script.Parent == ReplicatedStorage, "Cannot invoke legacy mode if not at ReplicatedStorage.Nevermore")

	if not RunService:IsRunning() then
		error("Test mode not supported")
	elseif RunService:IsServer() and RunService:IsClient() or (not RunService:IsRunning()) then
		if RunService:IsRunning() then
			error("Warning: Loading all modules in PlaySolo. It's recommended you use accurate play solo.")
		end
	elseif RunService:IsServer() then
		local container = ServerScriptService:FindFirstChild("Nevermore") or error("No ServerScriptService.Nevermore folder")
		local clientFolder, serverFolder, sharedFolder = LoaderUtils.toWallyFormat(container)

		clientFolder.Name = "_nevermoreClient"
		clientFolder.Parent = ReplicatedStorage

		sharedFolder.Name = "_nevermoreShared"
		sharedFolder.Parent = ReplicatedStorage

		serverFolder.Name = "_nevermoreServer"
		serverFolder.Parent = ServerScriptService

		rawset(self, "_container", serverFolder)
		self:_buildLookupContainer()
	elseif RunService:IsClient() then
		local container = ReplicatedStorage:WaitForChild("_nevermoreClient", 2)

		if not container then
			warn("[Nevermore] - Be sure to call require(ServerScriptService.Nevermore) on the server to replicate nevermore")
			container = ReplicatedStorage:WaitForChild("_nevermoreClient")
		end

		rawset(self, "_container", container)
		self:_buildLookupContainer()
	else
		error("Error: Unknown RunService state (Not client/server/test mode)")
	end
end

return LegacyLoader
