function methods.InternalApplyRobloxFilter(M,j,H,A)if RunService:IsServer()and not RunService:IsStudio()then local l=M:GetSpeaker(j)local L=A and M:GetSpeaker(A)if l==nil then return nil end local E=l:GetPlayer()local P=L and L:GetPlayer()if E==nil then return H end local D=tick()local n=0 while true do local j,A=pcall(function()if P then return Chat:FilterStringAsync(H,E,P)else return Chat:FilterStringForBroadcast(H,E)end end)if j then return A else warn("\069\114\114\111\114 \102\105\108\116\101\114\105\110\103 \109\101\115\115\097\103\101\058",A)end n=n+1 if n>MAX_FILTER_RETRIES or tick()-D>MAX_FILTER_DURATION then M:InternalNotifyFilterIssue()return nil end local l=FILTER_BACKOFF_INTERVALS[math.min(#FILTER_BACKOFF_INTERVALS,n)]local L=l+(math.random()*2-1)*l wait(L)end else if not StudioMessageFilteredCache[H]then StudioMessageFilteredCache[H]=true wait(.2)end return H end return nil end function methods.InternalDoMessageFilter(M,j,H,A)local l=M.FilterMessageFunctions:GetIterator()for M,l,L in l do local E,P=pcall(function()l(j,H,A)end)if not E then warn(string.format("\068\111\077\101\115\115\097\103\101\070\105\108\116\101\114 \070\117\110\099\116\105\111\110 \'\037\115\' \102\097\105\108\101\100 \102\111\114 \114\101\097\115\111\110\058 \037\115",M,P))end end end function methods.InternalDoProcessCommands(M,j,H,A)local l=M.ProcessCommandsFunctions:GetIterator()for M,l,L in l do local E,P=pcall(function()local M=l(j,H,A)if type(M)~="\098\111\111\108\101\097\110"then error("\080\114\111\099\101\115\115 \099\111\109\109\097\110\100 \102\117\110\099\116\105\111\110\115 \109\117\115\116 \114\101\116\117\114\110 \097 \098\111\111\108")end return M end)if not E then warn(string.format("\068\111\080\114\111\099\101\115\115\067\111\109\109\097\110\100\115 \070\117\110\099\116\105\111\110 \'\037\115\' \102\097\105\108\101\100 \102\111\114 \114\101\097\115\111\110\058 \037\115",M,P))elseif P then return true end end return false end function methods.InternalGetUniqueMessageId(j)local H=j.MessageIdCounter j.MessageIdCounter=H+1 return H end function methods.InternalAddSpeakerWithPlayerObject(M,j,H,A)if M.Speakers[j:lower()]then error("\083\112\101\097\107\101\114 \""..(j.."\" \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"))end local l=Speaker.new(M,j)l:InternalAssignPlayerObject(H)M.Speakers[j:lower()]=l if A then local H,A=pcall(function()M.eSpeakerAdded:Fire(j)end)if not H and A then print("\069\114\114\111\114 \097\100\100\105\110\103 \115\112\101\097\107\101\114\058 "..A)end end return l end function methods.InternalFireSpeakerAdded(H,j)local A,M=pcall(function()H.eSpeakerAdded:Fire(j)end)if not A and M then print("\069\114\114\111\114 \102\105\114\105\110\103 \115\112\101\097\107\101\114 \097\100\100\101\100\058 "..M)end end

function methods:InternalApplyRobloxFilter(speakerName, message, toSpeakerName)
	if (RunService:IsServer() and not RunService:IsStudio()) then
		local fromSpeaker = self:GetSpeaker(speakerName)
		local toSpeaker = toSpeakerName and self:GetSpeaker(toSpeakerName)

		if fromSpeaker == nil then
			return nil
		end

		local fromPlayerObj = fromSpeaker:GetPlayer()
		local toPlayerObj = toSpeaker and toSpeaker:GetPlayer()

		if fromPlayerObj == nil then
			return message
		end

		local filterStartTime = tick()
		local filterRetries = 0
		while true do
			local success, message = pcall(function()
				if toPlayerObj then
					return Chat:FilterStringAsync(message, fromPlayerObj, toPlayerObj)
				else
					return Chat:FilterStringForBroadcast(message, fromPlayerObj)
				end
			end)
			if success then
				return message
			else
				warn("Error filtering message:", message)
			end
			filterRetries = filterRetries + 1
			if filterRetries > MAX_FILTER_RETRIES or (tick() - filterStartTime) > MAX_FILTER_DURATION then
				self:InternalNotifyFilterIssue()
				return nil
			end
			local backoffInterval = FILTER_BACKOFF_INTERVALS[math.min(#FILTER_BACKOFF_INTERVALS, filterRetries)]
			-- backoffWait = backoffInterval +/- (0 -> backoffInterval)
			local backoffWait = backoffInterval + ((math.random()*2 - 1) * backoffInterval)
			wait(backoffWait)
		end
	else
		--// Simulate filtering latency.
		--// There is only latency the first time the message is filtered, all following calls will be instant.
		if not StudioMessageFilteredCache[message] then
			StudioMessageFilteredCache[message] = true
			wait(0.2)
		end
		return message
	end

	return nil
end

function methods:InternalDoMessageFilter(speakerName, messageObj, channel)
	local filtersIterator = self.FilterMessageFunctions:GetIterator()

	for funcId, func, priority in filtersIterator do
		local success, errorMessage = pcall(function()
			func(speakerName, messageObj, channel)
		end)

		if not success then
			warn(string.format("DoMessageFilter Function '%s' failed for reason: %s", funcId, errorMessage))
		end
	end
end

function methods:InternalDoProcessCommands(speakerName, message, channel)
	local commandsIterator = self.ProcessCommandsFunctions:GetIterator()

	for funcId, func, priority in commandsIterator do
		local success, returnValue = pcall(function()
			local ret = func(speakerName, message, channel)
			if type(ret) ~= "boolean" then
				error("Process command functions must return a bool")
			end
			return ret
		end)

		if not success then
			warn(string.format("DoProcessCommands Function '%s' failed for reason: %s", funcId, returnValue))
		elseif returnValue then
			return true
		end
	end

	return false
end

function methods:InternalGetUniqueMessageId()
	local id = self.MessageIdCounter
	self.MessageIdCounter = id + 1
	return id
end

function methods:InternalAddSpeakerWithPlayerObject(speakerName, playerObj, fireSpeakerAdded)
	if (self.Speakers[speakerName:lower()]) then
		error("Speaker \"" .. speakerName .. "\" already exists!")
	end

	local speaker = Speaker.new(self, speakerName)
	speaker:InternalAssignPlayerObject(playerObj)
	self.Speakers[speakerName:lower()] = speaker

	if fireSpeakerAdded then
		local success, err = pcall(function() self.eSpeakerAdded:Fire(speakerName) end)
		if not success and err then
			print("Error adding speaker: " ..err)
		end
	end

	return speaker
end

function methods:InternalFireSpeakerAdded(speakerName)
	local success, err = pcall(function() self.eSpeakerAdded:Fire(speakerName) end)
	if not success and err then
		print("Error firing speaker added: " ..err)
	end
end
