local s=game:GetService("\082\117\110\083\101\114\118\105\099\101")local Q={}Q.__index=Q local a={InputChanged=true}local i={}local function q(...)local s=...if s and(typeof(s)=="\073\110\115\116\097\110\099\101"and s:IsA("\073\110\112\117\116\079\098\106\101\099\116"))then return{Delta=s.Delta;KeyCode=s.KeyCode;Position=s.Position,UserInputState=s.UserInputState,UserInputType=s.UserInputType}end return...end local U={}Q.clientActions={connect=function(Q,z,u)local N=z if type(z)=="\115\116\114\105\110\103"then z=game:GetService(z)end if U[z]==nil then U[z]={}end U[z][u]=z[u]:Connect(function(...)if a[u]and not s:IsStudio()then local s=table.pack(q(...))if i[z]and i[z][u]then i[z][u]=s else if i[z]==nil then i[z]={}end i[z][u]=s task.delay(.25,function()local s=i[z][u]Q("\101\118\101\110\116",N,u,unpack(s,1,s.n))i[z][u]=nil if next(i[z])==nil then i[z]=nil end end)end return end Q("\101\118\101\110\116",N,u,q(...))end)end;disconnect=function(s,Q,a)if type(Q)=="\115\116\114\105\110\103"then Q=game:GetService(Q)end if U[Q]and U[Q][a]then U[Q][a]:Disconnect()U[Q][a]=nil end end}function Q.new(s)return setmetatable({_fire=s;_storage={},players={}},Q)end function Q.connect(q,Q,a,i)if s:IsClient()then return Q[a]:Connect(i)end if not game:IsAncestorOf(Q)then local s s=Q.AncestryChanged:Connect(function()if s==nil then return end if game:IsAncestorOf(Q)then s:Disconnect()s=nil q:connect(Q,a,i)end end)return end if q._storage[Q]==nil then q._storage[Q]={}Q.Destroying:Connect(function()for s in q._storage[Q]do q:_disconnect(Q,s)end end)end q._storage[Q][a]=i for s,i in q.players do q:_connectPlayerEvent(i,Q,a)end return{Disconnect=function()q:_disconnect(Q,a)end}end function Q._connectPlayerEvent(i,s,Q,a)if Q.Parent==game then Q=Q.ClassName end i._fire(s,"\099\111\110\110\101\099\116",Q,a)end function Q._disconnectPlayerEvent(i,s,Q,a)if Q.Parent==game then Q=Q.ClassName end i._fire(s,"\100\105\115\099\111\110\110\101\099\116",Q,a)end function Q.connectPlayer(Q,s)for a,i in Q._storage do for i in i do Q:_connectPlayerEvent(s,a,i)end end table.insert(Q.players,s)end function Q.disconnectPlayer(Q,s)local a=table.find(Q.players,s)if not a then return end table.remove(Q.players,a)for a,i in Q._storage do for i in i do Q:_disconnectPlayerEvent(s,a,i)end end end function Q._disconnect(a,s,Q)a._storage[s][Q]=nil for i,q in a.players do a:_disconnectPlayerEvent(q,s,Q)end end function Q.fireEventFromPlayer(i,s,Q,a,...)if not table.find(i.players,s)then warn(s,"\102\105\114\101\100 \097 \100\101\098\117\103\103\101\114 \101\118\101\110\116 \098\117\116 \116\104\101\121 \097\114\101\110\'\116 \097\117\116\104\111\114\105\122\101\100")return end if type(Q)=="\115\116\114\105\110\103"then Q=game:GetService(Q)end if not i._storage[Q]or not i._storage[Q][a]then return end i._storage[Q][a](...)end return Q
local RunService = game:GetService("RunService")
local EventBridge = {}
EventBridge.__index = EventBridge

local debouncedEvents = {
	InputChanged = true,
}

local debounce = {}

local function serialize(...)
	local first = ...

	if first and typeof(first) == "Instance" and first:IsA("InputObject") then
		return {
			Delta = first.Delta,
			KeyCode = first.KeyCode,
			Position = first.Position,
			UserInputState = first.UserInputState,
			UserInputType = first.UserInputType,
		}
	end

	return ...
end

local clientConnections = {}
EventBridge.clientActions = {
	connect = function(fire, instance, event)
		local instanceFromServer = instance

		if type(instance) == "string" then
			instance = game:GetService(instance)
		end

		if clientConnections[instance] == nil then
			clientConnections[instance] = {}
		end

		clientConnections[instance][event] = instance[event]:Connect(function(...)
			if debouncedEvents[event] and not RunService:IsStudio() then
				local args = table.pack(serialize(...))

				if debounce[instance] and debounce[instance][event] then
					debounce[instance][event] = args
				else
					if debounce[instance] == nil then
						debounce[instance] = {}
					end

					debounce[instance][event] = args

					task.delay(0.25, function()
						local args = debounce[instance][event]

						fire("event", instanceFromServer, event, unpack(args, 1, args.n))

						debounce[instance][event] = nil

						if next(debounce[instance]) == nil then
							debounce[instance] = nil
						end
					end)
				end

				return
			end

			fire("event", instanceFromServer, event, serialize(...))
		end)
	end,

	disconnect = function(_fire, instance, event)
		if type(instance) == "string" then
			instance = game:GetService(instance)
		end

		if clientConnections[instance] and clientConnections[instance][event] then
			clientConnections[instance][event]:Disconnect()
			clientConnections[instance][event] = nil
		end
	end,
}

function EventBridge.new(fire)
	return setmetatable({
		_fire = fire,
		_storage = {},
		players = {},
	}, EventBridge)
end

function EventBridge:connect(instance, event, handler)
	if RunService:IsClient() then
		return instance[event]:Connect(handler)
	end

	if not game:IsAncestorOf(instance) then
		local connection

		connection = instance.AncestryChanged:Connect(function()
			if connection == nil then
				return
			end

			if game:IsAncestorOf(instance) then
				connection:Disconnect()
				connection = nil
				self:connect(instance, event, handler)
			end
		end)

		return
	end

	if self._storage[instance] == nil then
		self._storage[instance] = {}

		instance.Destroying:Connect(function()
			for event in self._storage[instance] do
				self:_disconnect(instance, event)
			end
		end)
	end

	self._storage[instance][event] = handler

	for _, player in self.players do
		self:_connectPlayerEvent(player, instance, event)
	end

	return {
		Disconnect = function()
			self:_disconnect(instance, event)
		end,
	}
end

function EventBridge:_connectPlayerEvent(player, instance, event)
	if instance.Parent == game then
		instance = instance.ClassName
	end

	self._fire(player, "connect", instance, event)
end

function EventBridge:_disconnectPlayerEvent(player, instance, event)
	if instance.Parent == game then
		instance = instance.ClassName
	end

	self._fire(player, "disconnect", instance, event)
end

function EventBridge:connectPlayer(player)
	for instance, events in self._storage do
		for event in events do
			self:_connectPlayerEvent(player, instance, event)
		end
	end

	table.insert(self.players, player)
end

function EventBridge:disconnectPlayer(player)
	local index = table.find(self.players, player)

	if not index then
		return
	end

	table.remove(self.players, index)

	for instance, events in self._storage do
		for event in events do
			self:_disconnectPlayerEvent(player, instance, event)
		end
	end
end

function EventBridge:_disconnect(instance, event)
	self._storage[instance][event] = nil

	for _, player in self.players do
		self:_disconnectPlayerEvent(player, instance, event)
	end
end

function EventBridge:fireEventFromPlayer(player, instance, event, ...)
	if not table.find(self.players, player) then
		warn(player, "fired a debugger event but they aren't authorized")
		return
	end

	if type(instance) == "string" then
		instance = game:GetService(instance)
	end

	if not self._storage[instance] or not self._storage[instance][event] then
		-- warn(player, "fired a debugger event but the instance has no connections")
		return
	end

	self._storage[instance][event](...)
end

return EventBridge
