function Dispatcher.RunHooks(Z,o,D,...)if not Z.Registry.Hooks[o]then error(("\073\110\118\097\108\105\100 \104\111\111\107 \110\097\109\101\058 \037\113"):format(o),2)end if o=="\066\101\102\111\114\101\082\117\110"and(#Z.Registry.Hooks[o]==0 and(D.Group~="\068\101\102\097\117\108\116\085\116\105\108"and(D.Group~="\085\115\101\114\065\108\105\097\115"and D:HasImplementation())))then if RunService:IsStudio()then if displayedBeforeRunHookWarning==false then D:Reply((RunService:IsServer()and"\060\083\101\114\118\101\114\062"or"\060\067\108\105\101\110\116\062").." \067\111\109\109\097\110\100\115 \119\105\108\108 \110\111\116 \114\117\110 \105\110-\103\097\109\101 \105\102 \110\111 \066\101\102\111\114\101\082\117\110 \104\111\111\107 \105\115 \099\111\110\102\105\103\117\114\101\100\046 \076\101\097\114\110 \109\111\114\101\058 \104\116\116\112\115\058\047\047\101\114\121\110\046\105\111\047\067\109\100\114\047\103\117\105\100\101\047\072\111\111\107\115\046\104\116\109\108",Color3.fromRGB(255,228,26))displayedBeforeRunHookWarning=true end else return"\067\111\109\109\097\110\100 \098\108\111\099\107\101\100 \102\111\114 \115\101\099\117\114\105\116\121 \097\115 \110\111 \066\101\102\111\114\101\082\117\110 \104\111\111\107 \105\115 \099\111\110\102\105\103\117\114\101\100\046"end end for o,Z in ipairs(Z.Registry.Hooks[o])do local r=Z.callback(D,...)if r~=nil then return tostring(r)end end end function Dispatcher.PushHistory(D,o)assert(RunService:IsClient(),"\080\117\115\104\072\105\115\116\111\114\121 \109\097\121 \111\110\108\121 \098\101 \117\115\101\100 \102\114\111\109 \116\104\101 \099\108\105\101\110\116\046")local Z=D:GetHistory()if Util.TrimString(o)==""or o==Z[#Z]then return end Z[#Z+1]=o TeleportService:SetTeleportSetting(HISTORY_SETTING_NAME,Z)end function Dispatcher.GetHistory(o)assert(RunService:IsClient(),"\071\101\116\072\105\115\116\111\114\121 \109\097\121 \111\110\108\121 \098\101 \117\115\101\100 \102\114\111\109 \116\104\101 \099\108\105\101\110\116\046")return TeleportService:GetTeleportSetting(HISTORY_SETTING_NAME)or{}end return function(o)Dispatcher.Cmdr=o Dispatcher.Registry=o.Registry return Dispatcher end

function Dispatcher:RunHooks(hookName, commandContext, ...)
	if not self.Registry.Hooks[hookName] then
		error(("Invalid hook name: %q"):format(hookName), 2)
	end

	if
		hookName == "BeforeRun"
		and #self.Registry.Hooks[hookName] == 0
		and commandContext.Group ~= "DefaultUtil"
		and commandContext.Group ~= "UserAlias"
		and commandContext:HasImplementation()
	then

		if RunService:IsStudio() then
			if displayedBeforeRunHookWarning == false then
				commandContext:Reply((RunService:IsServer() and "<Server>" or "<Client>") .. " Commands will not run in-game if no BeforeRun hook is configured. Learn more: https://eryn.io/Cmdr/guide/Hooks.html", Color3.fromRGB(255,228,26))
				displayedBeforeRunHookWarning = true
			end
		else
			return "Command blocked for security as no BeforeRun hook is configured."
		end
	end

	for _, hook in ipairs(self.Registry.Hooks[hookName]) do
		local value = hook.callback(commandContext, ...)

		if value ~= nil then
			return tostring(value)
		end
	end
end

function Dispatcher:PushHistory(text)
	assert(RunService:IsClient(), "PushHistory may only be used from the client.")

	local history = self:GetHistory()

	-- Remove duplicates
	if Util.TrimString(text) == "" or text == history[#history] then
		return
	end

	history[#history + 1] = text

	TeleportService:SetTeleportSetting(HISTORY_SETTING_NAME, history)
end

function Dispatcher:GetHistory()
	assert(RunService:IsClient(), "GetHistory may only be used from the client.")

	return TeleportService:GetTeleportSetting(HISTORY_SETTING_NAME) or {}
end

return function (cmdr)
	Dispatcher.Cmdr = cmdr
	Dispatcher.Registry = cmdr.Registry

	return Dispatcher
end
