Hotkeys={}function AssignHotkey(g,p)if type(g)=="\117\115\101\114\100\097\116\097"then g={g}elseif type(g)=="\115\116\114\105\110\103"then g={Enum.KeyCode[g]}elseif type(g)=="\116\097\098\108\101"then for p,J in ipairs(g)do if type(J)=="\115\116\114\105\110\103"then g[p]=Enum.KeyCode[J]end end end table.insert(Hotkeys,{Keys=g;Callback=p})end function EnableHotkeys()Connections.Hotkeys=Support.AddUserInputListener("\066\101\103\097\110","\075\101\121\098\111\097\114\100",false,function(g)local p=Support.GetListMembers(UserInputService:GetKeysPressed(),"\075\101\121\067\111\100\101")local J={}local I=Support.FlipTable({"\076\101\102\116\065\108\116","\087","\083","\065","\068","\083\112\097\099\101"})for g,p in ipairs(p)do if not I[p.Name]then table.insert(J,p)end end local w=#J table.sort(Hotkeys,function(g,p)if#g.Keys>#p.Keys then return true end end)for g,p in ipairs(Hotkeys)do if w==#p.Keys then local g=Support.FlipTable(p.Keys)local I=0 for p,J in pairs(J)do if g[J]then I=I+1 end end if I==w then p.Callback()break end end end end)end Enabling=Signal.new()Disabling=Signal.new()Enabled=Signal.new()Disabled=Signal.new()function Enable(g)if IsEnabled and not IsDisabling or IsEnabling then return elseif IsDisabling then Disabled:Wait()return Enable(g)end IsEnabling=true Enabling:Fire();(getfenv(0)).Mouse=g UserInputService.MouseBehavior=Enum.MouseBehavior.Default if Mode=="\084\111\111\108"then coroutine.resume(coroutine.create(function()SyncAPI:Invoke("\083\101\116\077\111\117\115\101\076\111\099\107\069\110\097\098\108\101\100",false)end))end while not UI do wait(.1)end UI.Parent=UIContainer if not Core.StartupNotificationsDisplayed then local g=require((Tool:WaitForChild("\085\073")):WaitForChild("\078\111\116\105\102\105\099\097\116\105\111\110\115"))local p=Roact.createElement(g,{Core=Core})Roact.mount(p,UI,"\078\111\116\105\102\105\099\097\116\105\111\110\115")Core.StartupNotificationsDisplayed=true end EnableHotkeys()Targeting:EnableTargeting()Selection.EnableOutlines()Selection.EnableMultiselectionHotkeys()if Mode=="\080\108\117\103\105\110"then local g Connections.StudioSelectionListener=SelectionService.SelectionChanged:Connect(function()local p={}g=p RunService.Heartbeat:Wait()if g==p then Selection.Replace(SelectionService:Get(),false)end end)end EquipTool(CurrentTool or require(Tool.Tools.Move))IsEnabled=true IsEnabling=false Enabled:Fire()end function Disable()if not IsEnabled and not IsEnabling or IsDisabling then return elseif IsEnabling then Enabled:Wait()return Disable()end IsDisabling=true Disabling:Fire()if Mode=="\084\111\111\108"then coroutine.resume(coroutine.create(function()SyncAPI:Invoke("\083\101\116\077\111\117\115\101\076\111\099\107\069\110\097\098\108\101\100",true)end))end if UI then UI.Parent=script end if CurrentTool then CurrentTool:Unequip()CurrentTool.Equipped=false end ClearConnections()IsEnabled=false IsDisabling=false Disabled:Fire()end
-- Core hotkeys
Hotkeys = {}

function AssignHotkey(Hotkey, Callback)
	-- Assigns the given hotkey to `Callback`

	-- Standardize enum-described hotkeys
	if type(Hotkey) == "userdata" then
		Hotkey = { Hotkey }

	-- Standardize string-described hotkeys
	elseif type(Hotkey) == "string" then
		Hotkey = { Enum.KeyCode[Hotkey] }

	-- Standardize string table-described hotkeys
	elseif type(Hotkey) == "table" then
		for Index, Key in ipairs(Hotkey) do
			if type(Key) == "string" then
				Hotkey[Index] = Enum.KeyCode[Key]
			end
		end
	end

	-- Register the hotkey
	table.insert(Hotkeys, { Keys = Hotkey, Callback = Callback })
end

function EnableHotkeys()
	-- Begins to listen for hotkey triggering

	-- Listen for pressed keys
	Connections.Hotkeys = Support.AddUserInputListener("Began", "Keyboard", false, function(Input)
		local _PressedKeys = Support.GetListMembers(UserInputService:GetKeysPressed(), "KeyCode")

		-- Filter out problematic keys
		local PressedKeys = {}
		local FilteredKeys = Support.FlipTable({ "LeftAlt", "W", "S", "A", "D", "Space" })
		for _, Key in ipairs(_PressedKeys) do
			if not FilteredKeys[Key.Name] then
				table.insert(PressedKeys, Key)
			end
		end

		-- Count pressed keys
		local KeyCount = #PressedKeys

		-- Prioritize hotkeys based on # of required keys
		table.sort(Hotkeys, function(A, B)
			if #A.Keys > #B.Keys then
				return true
			end
		end)

		-- Identify matching hotkeys
		for _, Hotkey in ipairs(Hotkeys) do
			if KeyCount == #Hotkey.Keys then
				-- Get the hotkey's key index
				local Keys = Support.FlipTable(Hotkey.Keys)
				local MatchingKeys = 0

				-- Check matching pressed keys
				for _, PressedKey in pairs(PressedKeys) do
					if Keys[PressedKey] then
						MatchingKeys = MatchingKeys + 1
					end
				end

				-- Trigger the first matching hotkey's callback
				if MatchingKeys == KeyCount then
					Hotkey.Callback()
					break
				end
			end
		end
	end)
end

Enabling = Signal.new()
Disabling = Signal.new()
Enabled = Signal.new()
Disabled = Signal.new()

function Enable(Mouse)
	-- Ensure tool is disabled or disabling, and not already enabling
	if (IsEnabled and not IsDisabling) or IsEnabling then
		return

	-- If tool is disabling, enable it once fully disabled
	elseif IsDisabling then
		Disabled:Wait()
		return Enable(Mouse)
	end

	-- Indicate that tool is enabling
	IsEnabling = true
	Enabling:Fire()

	-- Update the core mouse
	getfenv(0).Mouse = Mouse

	-- Use default mouse behavior
	UserInputService.MouseBehavior = Enum.MouseBehavior.Default

	-- Disable mouse lock in tool mode
	if Mode == "Tool" then
		coroutine.resume(coroutine.create(function()
			SyncAPI:Invoke("SetMouseLockEnabled", false)
		end))
	end

	-- Wait for UI to initialize asynchronously
	while not UI do
		wait(0.1)
	end

	-- Show UI
	UI.Parent = UIContainer

	-- Display startup notifications
	if not Core.StartupNotificationsDisplayed then
		local NotificationsComponent = require(Tool:WaitForChild("UI"):WaitForChild("Notifications"))
		local NotificationsElement = Roact.createElement(NotificationsComponent, {
			Core = Core,
		})
		Roact.mount(NotificationsElement, UI, "Notifications")
		Core.StartupNotificationsDisplayed = true
	end

	-- Start systems
	EnableHotkeys()
	Targeting:EnableTargeting()
	Selection.EnableOutlines()
	Selection.EnableMultiselectionHotkeys()

	-- Sync studio selection in
	if Mode == "Plugin" then
		local LastSelectionChangeHandle
		Connections.StudioSelectionListener = SelectionService.SelectionChanged:Connect(function()
			local SelectionChangeHandle = {}
			LastSelectionChangeHandle = SelectionChangeHandle

			-- Replace selection if it hasn't changed in a heartbeat
			RunService.Heartbeat:Wait()
			if LastSelectionChangeHandle == SelectionChangeHandle then
				Selection.Replace(SelectionService:Get(), false)
			end
		end)
	end

	-- Equip current tool
	EquipTool(CurrentTool or require(Tool.Tools.Move))

	-- Indicate that tool is now enabled
	IsEnabled = true
	IsEnabling = false
	Enabled:Fire()
end

function Disable()
	-- Ensure tool is enabled or enabling, and not already disabling
	if (not IsEnabled and not IsEnabling) or IsDisabling then
		return

	-- If tool is enabling, disable it once fully enabled
	elseif IsEnabling then
		Enabled:Wait()
		return Disable()
	end

	-- Indicate that tool is now disabling
	IsDisabling = true
	Disabling:Fire()

	-- Reenable mouse lock option in tool mode
	if Mode == "Tool" then
		coroutine.resume(coroutine.create(function()
			SyncAPI:Invoke("SetMouseLockEnabled", true)
		end))
	end

	-- Hide UI
	if UI then
		UI.Parent = script
	end

	-- Unequip current tool
	if CurrentTool then
		CurrentTool:Unequip()
		CurrentTool.Equipped = false
	end

	-- Clear temporary connections
	ClearConnections()

	-- Indicate that tool is now disabled
	IsEnabled = false
	IsDisabling = false
	Disabled:Fire()
end
