-- Garry's Mod Binder - Main Client Logic include("binder/sh_lang.lua") include("binder/core/sh_config.lua") include("binder/vgui/cl_frame.lua") include("binder/vgui/cl_profiles_tab.lua") include("binder/vgui/cl_keybind_tab.lua") include("binder/vgui/cl_radial_tab.lua") include("binder/vgui/cl_radial_hud.lua") include("binder/vgui/cl_settings_tab.lua") Binder = Binder or {} Binder.Profiles = Binder.Profiles or {} surface.CreateFont("Binder_Key", { font = "Roboto", size = 12, weight = 700, extended = true, }) CreateClientConVar("binder_show_feedback", "1", true, false) CreateClientConVar("binder_dark_theme", "1", true, false) CreateClientConVar("binder_radial_key", tostring(Binder.Config.DefaultRadialKey), true, false) -- Networking net.Receive("Binder_SyncProfiles", function() local length = net.ReadUInt(32) local compressed = net.ReadData(length) local data = util.Decompress(compressed) if data then Binder.Profiles = Binder.SanitizeProfiles(util.JSONToTable(data) or {}) if IsValid(Binder.Frame) then Binder.Frame:RefreshActiveTab() end end end) function Binder.SaveToServer() local data = util.TableToJSON(Binder.Profiles) local compressed = util.Compress(data) net.Start("Binder_UpdateProfile") net.WriteUInt(#compressed, 32) net.WriteData(compressed, #compressed) net.SendToServer() end -- Input Hook for Binds (Client-side Think for Singleplayer support) local PrevBindState = {} hook.Add("Think", "Binder_CheckBindsThink", function() local activeProfile for _, p in ipairs(Binder.Profiles or {}) do if p.Active then activeProfile = p break end end if not activeProfile or not activeProfile.Binds then return end -- Don't trigger new presses if in console, ESC menu, typing in chat, or focused on a VGUI text entry local blockNewInput = gui.IsConsoleVisible() or gui.IsGameUIVisible() or (vgui.GetKeyboardFocus() ~= nil) or LocalPlayer():IsTyping() for key, commandStr in pairs(activeProfile.Binds) do local isDown = input.IsButtonDown(key) local wasDown = PrevBindState[key] or false if isDown and not wasDown then if not blockNewInput then PrevBindState[key] = true if string.sub(commandStr, 1, 1) == "/" then LocalPlayer():ConCommand("say " .. commandStr) else LocalPlayer():ConCommand(commandStr) end end elseif not isDown and wasDown then PrevBindState[key] = false -- Automatically release + commands local cmd = string.Explode(" ", commandStr)[1] if cmd and string.sub(cmd, 1, 1) == "+" then local minusCmd = "-" .. string.sub(cmd, 2) LocalPlayer():ConCommand(minusCmd) end end end end) concommand.Add("binder_menu", function() if Binder.Frame and IsValid(Binder.Frame) then Binder.Frame:Remove() end Binder.Frame = vgui.Create("Binder_Frame") end)