local function w(w)local I={}for w,y in pairs(w)do I[w]=y end return I end local I={}local y={eDestroyed=true;eSaidMessage=true;eReceivedMessage=true,eReceivedUnfilteredMessage=true,eMessageDoneFiltering=true;eReceivedSystemMessage=true,eChannelJoined=true;eChannelLeft=true;eMuted=true,eUnmuted=true,eExtraDataUpdated=true,eMainChannelSet=true;eChannelNameColorUpdated=true}local p={Destroyed="\101\068\101\115\116\114\111\121\101\100";SaidMessage="\101\083\097\105\100\077\101\115\115\097\103\101";ReceivedMessage="\101\082\101\099\101\105\118\101\100\077\101\115\115\097\103\101",ReceivedUnfilteredMessage="\101\082\101\099\101\105\118\101\100\085\110\102\105\108\116\101\114\101\100\077\101\115\115\097\103\101",RecievedUnfilteredMessage="\101\082\101\099\101\105\118\101\100\085\110\102\105\108\116\101\114\101\100\077\101\115\115\097\103\101";MessageDoneFiltering="\101\077\101\115\115\097\103\101\068\111\110\101\070\105\108\116\101\114\105\110\103";ReceivedSystemMessage="\101\082\101\099\101\105\118\101\100\083\121\115\116\101\109\077\101\115\115\097\103\101";ChannelJoined="\101\067\104\097\110\110\101\108\074\111\105\110\101\100";ChannelLeft="\101\067\104\097\110\110\101\108\076\101\102\116",Muted="\101\077\117\116\101\100";Unmuted="\101\085\110\109\117\116\101\100";ExtraDataUpdated="\101\069\120\116\114\097\068\097\116\097\085\112\100\097\116\101\100",MainChannelSet="\101\077\097\105\110\067\104\097\110\110\101\108\083\101\116";ChannelNameColorUpdated="\101\067\104\097\110\110\101\108\078\097\109\101\067\111\108\111\114\085\112\100\097\116\101\100"}I.__index=function(w,x)local X=rawget(I,x)if X then return X end if y[x]and not rawget(w,x)then rawset(w,x,Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116"))end local B=p[x]if B and not rawget(w,x)then if not rawget(w,B)then rawset(w,B,Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116"))end rawset(w,x,(rawget(w,B)).Event)end return rawget(w,x)end function I.LazyFire(I,w,...)local y=rawget(I,w)if y then y:Fire(...)end end function I.SayMessage(p,w,I,y)if p.ChatService:InternalDoProcessCommands(p.Name,w,I)then return end if not I then return end local x=p.Channels[I:lower()]if not x then return end local X=x:InternalPostMessage(p,w,y)if X then pcall(function()p:LazyFire("\101\083\097\105\100\077\101\115\115\097\103\101",X,I)end)end return X end function I.JoinChannel(I,w)if I.Channels[w:lower()]then warn("\083\112\101\097\107\101\114 \105\115 \097\108\114\101\097\100\121 \105\110 \099\104\097\110\110\101\108 \""..(w.."\""))return end local y=I.ChatService:GetChannel(w)if not y then error("\067\104\097\110\110\101\108 \""..(w.."\" \100\111\101\115 \110\111\116 \101\120\105\115\116\033"))end I.Channels[w:lower()]=y y:InternalAddSpeaker(I)local p,x=pcall(function()I.eChannelJoined:Fire(y.Name,y:GetWelcomeMessageForSpeaker(I))end)if not p and x then print("\069\114\114\111\114 \106\111\105\110\105\110\103 \099\104\097\110\110\101\108\058 "..x)end end function I.LeaveChannel(I,w)if not I.Channels[w:lower()]then warn("\083\112\101\097\107\101\114 \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \""..(w.."\""))return end local y=I.Channels[w:lower()]I.Channels[w:lower()]=nil y:InternalRemoveSpeaker(I)local p,x=pcall(function()I:LazyFire("\101\067\104\097\110\110\101\108\076\101\102\116",y.Name)if I.PlayerObj then I.EventFolder.OnChannelLeft:FireClient(I.PlayerObj,y.Name)end end)if not p and x then print("\069\114\114\111\114 \108\101\097\118\105\110\103 \099\104\097\110\110\101\108\058 "..x)end end function I.IsInChannel(I,w)return I.Channels[w:lower()]~=nil end function I.GetChannelList(w)local I={}for w,y in pairs(w.Channels)do table.insert(I,y.Name)end return I end function I.SendMessage(x,w,I,y,p)local X=x.Channels[I:lower()]if X then X:SendMessageToSpeaker(w,x.Name,y,p)elseif RunService:IsStudio()then warn(string.format("\083\112\101\097\107\101\114 \'\037\115\' \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \'\037\115\' \097\110\100 \099\097\110\110\111\116 \114\101\099\101\105\118\101 \097 \109\101\115\115\097\103\101 \105\110 \105\116\046",x.Name,I))end end function I.SendSystemMessage(p,w,I,y)local x=p.Channels[I:lower()]if x then x:SendSystemMessageToSpeaker(w,p.Name,y)elseif RunService:IsStudio()then warn(string.format("\083\112\101\097\107\101\114 \'\037\115\' \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \'\037\115\' \097\110\100 \099\097\110\110\111\116 \114\101\099\101\105\118\101 \097 \115\121\115\116\101\109 \109\101\115\115\097\103\101 \105\110 \105\116\046",p.Name,I))end end function I.GetPlayer(w)return w.PlayerObj end function I.GetNameForDisplay(w)if ChatSettings.PlayerDisplayNamesEnabled then local I=w:GetPlayer()if I then return I.DisplayName else return w.Name end else return w.Name end end function I.SetExtraData(y,w,I)y.ExtraData[w]=I y:LazyFire("\101\069\120\116\114\097\068\097\116\097\085\112\100\097\116\101\100",w,I)end function I.GetExtraData(I,w)return I.ExtraData[w]end function I.SetMainChannel(I,w)local y,p=pcall(function()I:LazyFire("\101\077\097\105\110\067\104\097\110\110\101\108\083\101\116",w)if I.PlayerObj then I.EventFolder.OnMainChannelSet:FireClient(I.PlayerObj,w)end end)if not y and p then print("\069\114\114\111\114 \115\101\116\116\105\110\103 \109\097\105\110 \099\104\097\110\110\101\108\058 "..p)end end
--////////////////////////////// Methods
--//////////////////////////////////////
local function ShallowCopy(table)
	local copy = {}
	for i, v in pairs(table) do
		copy[i] = v
	end
	return copy
end

local methods = {}

local lazyEventNames = {
	eDestroyed = true,
	eSaidMessage = true,
	eReceivedMessage = true,
	eReceivedUnfilteredMessage = true,
	eMessageDoneFiltering = true,
	eReceivedSystemMessage = true,
	eChannelJoined = true,
	eChannelLeft = true,
	eMuted = true,
	eUnmuted = true,
	eExtraDataUpdated = true,
	eMainChannelSet = true,
	eChannelNameColorUpdated = true,
}
local lazySignalNames = {
	Destroyed = "eDestroyed",
	SaidMessage = "eSaidMessage",
	ReceivedMessage = "eReceivedMessage",
	ReceivedUnfilteredMessage = "eReceivedUnfilteredMessage",
	RecievedUnfilteredMessage = "eReceivedUnfilteredMessage", -- legacy mispelling
	MessageDoneFiltering = "eMessageDoneFiltering",
	ReceivedSystemMessage = "eReceivedSystemMessage",
	ChannelJoined = "eChannelJoined",
	ChannelLeft = "eChannelLeft",
	Muted = "eMuted",
	Unmuted = "eUnmuted",
	ExtraDataUpdated = "eExtraDataUpdated",
	MainChannelSet = "eMainChannelSet",
	ChannelNameColorUpdated = "eChannelNameColorUpdated",
}

methods.__index = function(self, k)
	local fromMethods = rawget(methods, k)
	if fromMethods then
		return fromMethods
	end

	if lazyEventNames[k] and not rawget(self, k) then
		rawset(self, k, Instance.new("BindableEvent"))
	end
	local lazySignalEventName = lazySignalNames[k]
	if lazySignalEventName and not rawget(self, k) then
		if not rawget(self, lazySignalEventName) then
			rawset(self, lazySignalEventName, Instance.new("BindableEvent"))
		end
		rawset(self, k, rawget(self, lazySignalEventName).Event)
	end
	return rawget(self, k)
end

function methods:LazyFire(eventName, ...)
	local createdEvent = rawget(self, eventName)
	if createdEvent then
		createdEvent:Fire(...)
	end
end

function methods:SayMessage(message, channelName, extraData)
	if self.ChatService:InternalDoProcessCommands(self.Name, message, channelName) then
		return
	end
	if not channelName then
		return
	end

	local channel = self.Channels[channelName:lower()]
	if not channel then
		return
	end

	local messageObj = channel:InternalPostMessage(self, message, extraData)
	if messageObj then
		pcall(function()
			self:LazyFire("eSaidMessage", messageObj, channelName)
		end)
	end

	return messageObj
end

function methods:JoinChannel(channelName)
	if self.Channels[channelName:lower()] then
		warn('Speaker is already in channel "' .. channelName .. '"')
		return
	end

	local channel = self.ChatService:GetChannel(channelName)
	if not channel then
		error('Channel "' .. channelName .. '" does not exist!')
	end

	self.Channels[channelName:lower()] = channel
	channel:InternalAddSpeaker(self)
	local success, err = pcall(function()
		self.eChannelJoined:Fire(channel.Name, channel:GetWelcomeMessageForSpeaker(self))
	end)
	if not success and err then
		print("Error joining channel: " .. err)
	end
end

function methods:LeaveChannel(channelName)
	if not self.Channels[channelName:lower()] then
		warn('Speaker is not in channel "' .. channelName .. '"')
		return
	end

	local channel = self.Channels[channelName:lower()]

	self.Channels[channelName:lower()] = nil
	channel:InternalRemoveSpeaker(self)
	local success, err = pcall(function()
		self:LazyFire("eChannelLeft", channel.Name)
		if self.PlayerObj then
			self.EventFolder.OnChannelLeft:FireClient(self.PlayerObj, channel.Name)
		end
	end)
	if not success and err then
		print("Error leaving channel: " .. err)
	end
end

function methods:IsInChannel(channelName)
	return (self.Channels[channelName:lower()] ~= nil)
end

function methods:GetChannelList()
	local list = {}
	for i, channel in pairs(self.Channels) do
		table.insert(list, channel.Name)
	end
	return list
end

function methods:SendMessage(message, channelName, fromSpeaker, extraData)
	local channel = self.Channels[channelName:lower()]
	if channel then
		channel:SendMessageToSpeaker(message, self.Name, fromSpeaker, extraData)
	elseif RunService:IsStudio() then
		warn(
			string.format(
				"Speaker '%s' is not in channel '%s' and cannot receive a message in it.",
				self.Name,
				channelName
			)
		)
	end
end

function methods:SendSystemMessage(message, channelName, extraData)
	local channel = self.Channels[channelName:lower()]
	if channel then
		channel:SendSystemMessageToSpeaker(message, self.Name, extraData)
	elseif RunService:IsStudio() then
		warn(
			string.format(
				"Speaker '%s' is not in channel '%s' and cannot receive a system message in it.",
				self.Name,
				channelName
			)
		)
	end
end

function methods:GetPlayer()
	return self.PlayerObj
end

function methods:GetNameForDisplay()
	if ChatSettings.PlayerDisplayNamesEnabled then
		local player = self:GetPlayer()

		if player then
			return player.DisplayName
		else
			return self.Name
		end
	else
		return self.Name
	end
end

function methods:SetExtraData(key, value)
	self.ExtraData[key] = value
	self:LazyFire("eExtraDataUpdated", key, value)
end

function methods:GetExtraData(key)
	return self.ExtraData[key]
end

function methods:SetMainChannel(channelName)
	local success, err = pcall(function()
		self:LazyFire("eMainChannelSet", channelName)
		if self.PlayerObj then
			self.EventFolder.OnMainChannelSet:FireClient(self.PlayerObj, channelName)
		end
	end)
	if not success and err then
		print("Error setting main channel: " .. err)
	end
end
