Загрузка данных




-- perfect user interface • gamesense
----- enQ#1349


print "pui debug"

-------------------------------------------------------------------------
-- #region :: Header


--
-- #region : Definitions

--#region: localization

local assert, defer, error, getfenv, setfenv, getmetatable, setmetatable, ipairs,
pairs, next, pcall, rawequal, rawset, rawlen, readfile, require, select,
tonumber, tostring, type, unpack, xpcall =
assert, defer, error, getfenv, setfenv, getmetatable, setmetatable, ipairs,
pairs, next, pcall, rawequal, rawset, rawlen, readfile, require, select,
tonumber, tostring, type, unpack, xpcall


local function mcopy (o)
	if type(o) ~= "table" then return o end
	local res = {} for k, v in pairs(o) do res[mcopy(k)] = mcopy(v) end return res
end

local table, math, string = mcopy(table), mcopy(math), mcopy(string)
local ui, client = mcopy(ui), mcopy(client)

--#endregion

--#region: globals

table.find = function (t, j)  for k, v in pairs(t) do if v == j then return k end end return false  end
table.ifind = function (t, j)  for i = 1, table.maxn(t) do if t[i] == j then return i end end  end
table.qfind = function (t, j)  for i = 1, #t do if t[i] == j then return i end end  end
table.ihas = function (t, ...) local arg = {...} for i = 1, table.maxn(t) do for j = 1, #arg do if t[i] == arg[j] then return true end end end return false end

table.minn = function (t) local s = 0 for i = 1, #t do if t[i] == nil then break end s = s + 1 end return s end
table.filter = function (t)  local res = {} for i = 1, table.maxn(t) do if t[i] ~= nil then res[#res+1] = t[i] end end return res  end
table.append = function (t, ...)  for i, v in ipairs{...} do table.insert(t, v) end  end
table.copy = mcopy

local ternary = function (c, a, b)  if c then return a else return b end  end
local contend = function (func, callback, ...)
	local t = { pcall(func, ...) }
	if not t[1] then return type(callback) == "function" and callback(t[2]) or error(t[2], callback or 2) end
	return unpack(t, 2)
end

--#endregion

--#region: directory tools

local dirs = {
	execute = function (t, path, func)
		local p, k for _, s in ipairs(path) do
			k, p, t = s, t, t[s]
			if t == nil then return end
		end
		if p[k] then func(p[k]) end
	end,
	replace = function (t, path, value)
		local p, k for _, s in ipairs(path) do
			k, p, t = s, t, t[s]
			if t == nil then return end
		end
		p[k] = value
	end,
	find = function (t, path)
		local p, k for _, s in ipairs(path) do
			k, p, t = s, t, t[s]
			if t == nil then return end
		end
		return p[k]
	end,
}

dirs.pave = function (t, place, path)
    local p = t for i, v in ipairs(path) do
        if type(p[v]) == "table" then p = p[v]
        else p[v] = (i < #path) and {} or place  p = p[v]  end
    end return t
end

dirs.extract = function (t, path)
	if not path or #path == 0 then return t end
    local j = dirs.find(t, path)
    return dirs.pave({}, j, path)
end

--#endregion

local pui, pui_mt, methods_mt = {}, {}, {
	element = {}, group = {}
}

-- #endregion
--

--
-- #region : Elements

--#region: arguments

local registry, ragebot, players = {}, {}, {}

local elements = {
	button		= { type = "function",	arg = 2, unsavable = true },
	checkbox	= { type = "boolean",	arg = 1, init = false	},
	color_picker= { type = "table",		arg = 5 },
	combobox	= { type = "string",	arg = 2, variable = true },
	hotkey		= { type = "table",		arg = 3, enum = {[0] = "Always on", "On hotkey", "Toggle", "Off hotkey"} },
	label		= { type = "string",	arg = 1, unsavable = true },
	listbox		= { type = "number",	arg = 2, init = 0, variable = true },
	multiselect	= { type = "table",		arg = 2, init = {}, variable = true },
	slider		= { type = "number",	arg = 8 },
	textbox		= { type = "string",	arg = 1, init = "" },
	string		= { type = "string",	arg = 2, init = "" },
	unknown		= { type = "string",	arg = 2, init = "" } -- new_string type
}

local weapons = { "Global", "G3SG1 / SCAR-20", "SSG 08", "AWP", "R8 Revolver", "Desert Eagle", "Pistol", "Zeus", "Rifle", "Shotgun", "SMG", "Machine gun" }

--#endregion

--#region: registry

local ui_mset = function (k, v)
	if registry[k].type == "hotkey" then
		ui.set(k, elements.hotkey.enum[ v[2] ], v[3])
	else
		ui.set(k, v)
	end
end

local ui_mget = function (k)
	if registry[k].type == "hotkey" then return { ui.get(k) } else return ui.get(k) end
end

do
	client.set_event_callback("shutdown", function ()
		for k, v in next, registry do
			if v.__ref and not v.__rage then
				if v.overridden then ui_mset(k, v.original) end
				ui.set_enabled(k, true)
				ui.set_visible(k, not v.__hidden)
			end
		end
		ragebot.cycle(function (active)
			for k, v in pairs(ragebot.context[active]) do
				if v ~= nil and registry[k].overridden then
					ui_mset(k, v)
				end
			end
		end, true)
	end)
	client.set_event_callback("pre_config_save", function ()
		for k, v in next, registry do
			if v.__ref and not v.__rage and v.overridden then
				v.ovr_restore = { ui_mget(k) }
				ui_mset(k, v.original)
			end
		end
		ragebot.cycle(function (active)
			for k, v in pairs(ragebot.context[active]) do
				if registry[k].overridden then
					ragebot.cache[active][k] = { ui_mget(k) }
					ui_mset(k, v)
				end
			end
		end, true)
	end)
	client.set_event_callback("post_config_save", function ()
		for k, v in next, registry do
			if v.__ref and not v.__rage and v.overridden then
				ui_mset(k, unpack(v.ovr_restore))
				v.ovr_restore = nil
			end
		end
		ragebot.cycle(function (active)
			for k, v in pairs(ragebot.context[active]) do
				if registry[k].overridden and ragebot.cache[active][k] ~= nil then
					ui_mset(k, unpack(ragebot.cache[active][k]))
					ragebot.cache[active][k] = nil
				end
			end
		end, true)
	end)
end

--#endregion

--#region: elemence

local elemence = {} do
	local callbacks = function (this, isref)
		if this.name == "Weapon type" and string.lower(registry[this.ref].tab) == "rage" then return ui.get(this.ref) end

		ui.set_callback(this.ref, function (self)
			if registry[self].__rage and ragebot.silent then return end
			for i = 0, #registry[self].callbacks, 1 do
				if type(registry[self].callbacks[i]) == "function" then registry[self].callbacks[i](this) end
			end
		end)

		if this.type == "button" then return
		elseif this.type == "color_picker" or this.type == "hotkey" then
			registry[this.ref].callbacks[0] = function (self) this.value = { ui.get(self.ref) } end
			return { ui.get(this.ref) }
		else
			registry[this.ref].callbacks[0] = function (self) this.value = ui.get(self.ref) end
			if this.type == "multiselect" then
				this.value = ui.get(this.ref)
				registry[this.ref].callbacks[1] = function (self)
					registry[this.ref].options = {}
					for i = 1, #self.value do registry[this.ref].options[ self.value[i] ] = true end
				end
				registry[this.ref].callbacks[1](this)
			end
			return ui.get(this.ref)
		end
	end

	elemence.new = function (ref, add)
		local self = {}; add = add or {}

		self.ref = ref
		self.name, self.type = ui.name(ref), ui.type(ref)

		--
		registry[ref] = registry[ref] or {
			type = self.type, ref = ref, tab = add.__tab, container = add.__container,
			__ref = add.__ref, __hidden = add.__hidden, __init = add.__init, __list = add.__list, __rage = add.__rage,
			__plist = add.__plist and not (self.type == "label" or self.type == "button" or self.type == "hotkey"),

			overridden = false, original = self.value, donotsave = add.__plist or false,
			callbacks = { [0] = add.__callback }, events = {}, depend = { [0] = {ref}, {}, {} },
		}

		registry[ref].self = setmetatable(self, methods_mt.element)
		self.value = callbacks(self, add.__ref)

		if add.__rage then
			methods_mt.element.set_callback(self, ragebot.memorize)
		end
		if registry[ref].__plist then
			players.elements[#players.elements+1] = self
			methods_mt.element.set_callback(self, players.slot_update, true)
		end

		return self
	end

	elemence.group = function (...)
		return setmetatable({ ... }, methods_mt.group)
	end

	elemence.string = function (name, default)
		local this = {}

		this.ref = ui.new_string(name, default or "")
		this.type = "string"
		this[0] = {savable = true}

		return setmetatable(this, methods_mt.element)
	end

	elemence.features = function (self, args)
		do
			local addition
			local v, kind = args[1], type(args[1])

			if not addition and (kind == "table" or kind == "cdata") and not v.r then
				addition = "color"
				local r, g, b, a = v[1] or 255, v[2] or 255, v[3] or 255, v[4] or 255
				self.color = elemence.new( ui.new_color_picker(registry[self.ref].tab, registry[self.ref].container, self.name, r, g, b, a), {
					__init = { r, g, b, a },
					__plist = registry[self.ref].__plist
				} )
			elseif not addition and (kind == "table" or kind == "cdata") and v.r then
				addition = "color"
				self.color = elemence.new( ui.new_color_picker(registry[self.ref].tab, registry[self.ref].container, self.name, v.r, v.g, v.b, v.a), {
					__init = { v.r, v.g, v.b, v.a },
					__plist = registry[self.ref].__plist
				} )
			elseif not addition and kind == "number" then
				addition = "hotkey"
				self.hotkey = elemence.new( ui.new_hotkey(registry[self.ref].tab, registry[self.ref].container, self.name, true, v, {
					__init = v
				}) )
			end
			registry[self.ref].depend[0][2] = addition and self[addition].ref
			registry[self.ref].__addon = addition
		end
		do
			registry[self.ref].donotsave = args[2] == false
		end
	end

	elemence.memorize = function (self, path, origin)
		if registry[self.ref].donotsave then return end

		if not elements[self.type].unsavable then
			dirs.pave(origin, self.ref, path)
		end

		if self.color then
			path[#path] = path[#path] .. "_c"
			dirs.pave(origin, self.color.ref, path)
		end
		if self.hotkey then
			path[#path] = path[#path] .. "_h"
			dirs.pave(origin, self.hotkey.ref, path)
		end
	end

	elemence.hidden_refs = {
		"Unlock hidden cvars", "Allow custom game events", "Faster grenade toss",
		"sv_maxunlag", "sv_maxusrcmdprocessticks", "sv_clockcorrection_msecs", -- m4kb12jk
	}

	--#region: depend

	local cases = {
		combobox = function (v)
			if v[3] == true then
				return v[1].value ~= v[2]
			else
				for i = 2, #v do
					if v[1].value == v[i] then return true end
				end
			end
			return false
		end,
		listbox = function (v)
			if v[3] == true then
				return v[1].value ~= v[2]
			else
				for i = 2, #v do
					if v[1].value == v[i] then return true end
				end
			end
			return false
		end,
		multiselect = function (v)
			return table.ihas(v[1].value, unpack(v, 2))
		end,
		slider = function (v)
			return v[2] <= v[1].value and v[1].value <= (v[3] or v[2])
		end,
	}

	local depend = function (v)
		local condition = false

		if type(v[2]) == "function" then
			condition = v[2]( v[1] )
		else
			local f = cases[v[1].type]
			if f then condition = f(v)
			else condition = v[1].value == v[2] end
		end

		return condition and true or false
	end

	elemence.dependant = function (owner, dependant, dis)
		local count = 0

		for i = 1, #owner do
			if depend(owner[i]) then count = count + 1 else break end
		end

		local allow, action = count >= #owner, dis and "set_enabled" or "set_visible"

		for i, v in ipairs(dependant) do ui[action](v, allow) end
	end

	--#endregion
end

--#endregion

--#region: utils

local utils = {}

do
	utils.rgb_to_hex = function (color)
		return string.format("%02X%02X%02X%02X", color[1], color[2], color[3], color[4] or 255)
	end

	utils.hex_to_rgb = function (hex)
		hex = hex:gsub("^#", "")
		return tonumber(hex:sub(1, 2), 16), tonumber(hex:sub(3, 4), 16), tonumber(hex:sub(5, 6), 16), tonumber(hex:sub(7, 8), 16) or 255
	end

	utils.gradient_text = function (text, colors, precision)
		local symbols, length = {}, #string.gsub(text, ".[\128-\191]*", "a")
		local s = 1 / (#colors - 1)
		precision = precision or 1

		local i = 0
		for letter in string.gmatch(text, ".[\128-\191]*") do
			i = i + 1

			local weight = i / length
			local cw = weight / s
			local j = math.ceil(cw)
			local w = (cw / j)
			local L, R = colors[j], colors[j+1]

			local r = L[1] + (R[1] - L[1]) * w
			local g = L[2] + (R[2] - L[2]) * w
			local b = L[3] + (R[3] - L[3]) * w
			local a = L[4] + (R[4] - L[4]) * w

			symbols[#symbols+1] = ((i-1) % precision == 0) and ("\a%02x%02x%02x%02x%s"):format(r, g, b, a, letter) or letter
		end

		symbols[#symbols+1] = "\aCDCDCDFF"

		return table.concat(symbols)
	end

	local gradients = function (col, text)
		local colors = {}; for w in string.gmatch(col, "\b%x+") do
			colors[#colors+1] = { utils.hex_to_rgb( string.sub(w, 2) ) }
		end
		if #colors > 0 then return utils.gradient_text(text, colors, #text > 8 and 2 or 1) end
	end

	utils.format = function (s)
		if type(s) == "string" then
			s = string.gsub(s, "\f<(.-)>", pui.macros)
			s = string.gsub(s, "[\v\r\t]", {["\v"] = "\a".. pui.accent, ["\r"] = "\aCDCDCDFF", ["\t"] = "    "})
			s = string.gsub(s, "([\b%x]-)%[(.-)%]", gradients)
		end return s
	end

	utils.unpack_color = function (...)
		local arg = {...}
		local kind = type(arg[1])

		if kind == "table" or kind == "cdata" or kind == "userdata" then
			if arg[1].r then
				return {arg[1].r, arg[1].g, arg[1].b, arg[1].a}
			elseif arg[1][1] then
				return {arg[1][1], arg[1][2], arg[1][3], arg[1][4]}
			end
		end

		return arg
	end

	--#region: dispense

	local dispensers = {
		color_picker = function (args)
			args[1] = string.sub(utils.format(args[1]), 1, 117)

			if type(args[2]) ~= "number" then
				local col = args[2]
				args.n, args.req, args[2] = args.n + 3, args.req + 3, col.r
				table.insert(args, 3, col.g)
				table.insert(args, 4, col.b)
				table.insert(args, 5, col.a)
			end

			for i = args.req + 1, args.n do
				args.misc[i - args.req] = args[i]
			end

			args.data.__init = {args[2] or 255, args[3] or 255, args[4] or 255, args[5] or 255}
		end,
		listbox = function (args, variable)
			args[1] = string.sub(utils.format(args[1]), 1, 117)
			for i = args.req + 1, args.n do
				args.misc[i - args.req] = args[i]
			end

			args.data.__init, args.data.__list = 0, not variable and args[2] or {unpack(args, 2, args.n)}
		end,
		combobox = function (args, variable)
			args[1] = string.sub(utils.format(args[1]), 1, 117)
			for i = args.req + 1, args.n do
				args.misc[i - args.req] = args[i]
			end

			args.data.__init, args.data.__list = not variable and args[2][1] or args[2], not variable and args[2] or {unpack(args, 2, args.n)}
		end,
		multiselect = function (args, variable)
			args[1] = string.sub(utils.format(args[1]), 1, 117)
			for i = args.req + 1, args.n do
				args.misc[i - args.req] = args[i]
			end

			args.data.__init, args.data.__list = {}, not variable and args[2] or {unpack(args, 2, args.n)}
		end,
		slider = function (args)
			args[1] = string.sub(utils.format(args[1]), 1, 117)

			for i = args.req + 1, args.n do
				args.misc[i - args.req] = args[i]
			end

			args.data.__init = args[4] or args[2]
		end,
		button = function (args)
			args[2] = args[2] or function()end
			args[1] = string.sub(utils.format(args[1]), 1, 117)
			args.n, args.data.__callback = 2, args[2]
		end
	}

	utils.dispense = function (key, raw, ...)
		local args, group, ctx = {...}, {}, elements[key]

		if type(raw) == "table" then
			group[1], group[2] = raw[1], raw[2]
			group.__plist = raw.__plist
		else
			group[1], group[2] = raw, args[1]
			table.remove(args, 1)
		end

		args.n, args.data = table.maxn(args), {
			__tab = group[1], __container = group[2],
			__plist = group.__plist and true or nil
		}

		local variable = (ctx and ctx.variable) and type(args[2]) == "string"
		args.req, args.misc = not variable and ctx.arg or args.n, {}

		if dispensers[key] then
			dispensers[key](args, variable)
		else
			for i = 1, args.n do
				if type(args[i]) == "string" then
					args[i] = string.sub(utils.format(args[i]), 1, 117)
				end

				if i > args.req then args.misc[i - args.req] = args[i] end
			end
			args.data.__init = ctx.init
		end

		return args, group
	end

	--#endregion
end

--#endregion

-- #endregion
--


-- #endregion -----------------------------------------------------------
--


-------------------------------------------------------------------------
-- #region :: pui


--
-- #region : pui

--#region: variables

pui.macros = setmetatable({}, {
	__newindex = function (self, key, value) rawset(self, tostring(key), value) end,
	__index = function (self, key) return rawget(self, tostring(key)) end
})

pui.accent, pui.menu_open = nil, ui.is_menu_open()

do
	local reference = ui.reference("MISC", "Settings", "Menu color")
	pui.accent = utils.rgb_to_hex{ ui.get(reference) }
	local previous = pui.accent

	ui.set_callback(reference, function ()
		local color = { ui.get(reference) }
		pui.accent = utils.rgb_to_hex(color)

		for idx, ref in next, registry do
			if ref.type == "label" and not ref.__ref then
				local new, count = string.gsub(ref.self.value, previous, pui.accent)
				if count > 0 then
					ui.set(idx, new)
					ref.self.value = new
				end
			end
		end
		previous = pui.accent
		client.fire_event("pui::accent_color", color)
	end)
end

client.set_event_callback("paint_ui", function ()
	local state = ui.is_menu_open()
	if state ~= pui.menu_open then
		client.fire_event("pui::menu_state", state)
		pui.menu_open = state
	end
end)

--#endregion

--#region: features

pui.group = function (tab, container) return elemence.group(tab, container) end

pui.format = utils.format

pui.reference = function (tab, container, name)
	local found = { contend(ui.reference, 3, tab, container, name) }
	local total, hidden = #found, false

	-- done on purpose, don't blame me
	if string.lower(tab) == "misc" and string.lower(container) == "settings" then
		for i, v in ipairs(elemence.hidden_refs) do
			if string.find(name, "^" ..v) then hidden = true break end
		end
	end

	for i, v in ipairs(found) do
		found[i] = elemence.new(v, {
			__ref = true, __hidden = hidden or nil,
			__tab = tab, __container = container,
			__rage = string.lower(container) == "aimbot" or nil,
		})
	end

	if total > 1 then local shift = 0
		for i = 1, total > 4 and total or 4, 2 do
			local m, j = i - shift, i + 1 - shift
			if found[j] and (found[j].type == "hotkey" or found[j].type == "color_picker") then
				local addition = found[j].type == "color_picker" and "color" or "hotkey"
				registry[ found[m].ref ].__addon, found[m][addition] = addition, found[j]

				table.remove(found, j) shift = shift + 1
			end
		end return unpack(found)
	else return found[1] end
end

pui.traverse = function (t, f, p)
	p = p or {}

	if type(t) == "table" and t.__name ~= "pui::element" and t[#t] ~= "~" then
		for k, v in next, t do
			local np = table.copy(p); np[#np+1] = k
			pui.traverse(v, f, np)
		end
	else
		f(t, p)
	end
end

--#endregion

--#region: config system

do
	local save = function (config, ...)
		local packed = {}

		pui.traverse(dirs.extract(config, {...}), function (ref, path)
			local value
			local etype = registry[ref].type

			if etype == "color_picker" then
				value = "#".. utils.rgb_to_hex{ ui.get(ref) }
			elseif etype == "hotkey" then
				local _, mode, key = ui.get(ref)
				value = {mode, key or 0}
			else
				value = ui.get(ref)
			end

			if type(value) == "table" then value[#value+1] = "~" end
			dirs.pave(packed, value, path)
		end)

		return packed
	end

	local load = function (config, package, ...)
		if not package then return end

		local packed = dirs.extract(package, {...})
		pui.traverse(dirs.extract(config, {...}), function (ref, path)
			pcall(function ()
				local value, proxy = dirs.find(packed, path), registry[ref]
				local vtype, etype = type(value), proxy.type
				local object = elements[etype]

				if vtype == "string" and value:sub(1, 1) == "#" then
					value, vtype = { utils.hex_to_rgb(value) }, "table"
				elseif vtype == "table" and value[#value] == "~" then
					value[#value] = nil
				end

				if etype == "hotkey" and value and type(value[1]) == "number" then
					value[1] = elements.hotkey.enum[ value[1] ]
				end

				if object and object.type == vtype then
					if vtype == "table" and etype ~= "multiselect" then
						ui.set(ref, unpack(value))
						if etype == "color_picker" then methods_mt.element.invoke(proxy.self) end
					else
						ui.set(ref, value)
					end
				else
					if proxy.__init then ui.set(ref, proxy.__init) end
				end
			end)
		end)
	end

	--
	local package_mt = {
		__type = "pui::package", __metatable = false,
		__call = function (self, raw, ...)
			return (type(raw) == "table" and load or save)(self[0], raw, ...)
		end,
		save = function (self, ...) return save(self[0], ...) end,
		load = function (self, ...) load(self[0], ...) end,
	}	package_mt.__index = package_mt

	pui.setup = function (t)
		local package = { [0] = {} }
		pui.traverse(t, function (r, p) elemence.memorize(r, p, package[0]) end)
		return setmetatable(package, package_mt)
	end
end

--#endregion

-- #endregion
--

--
-- #region : methods

methods_mt.element = {
	__type = "pui::element", __name = "pui::element", __metatable = false,
	__eq = function (this, that) return this.ref == that.ref end,
	__tostring = function (self) return string.format('pui.%s[%d] "%s"', self.type, self.ref, self.name) end,
	__call = function (self, ...) if #{...} > 0 then ui.set(self.ref, ...) else return ui.get(self.ref) end end,

	--

	depend = function (self, ...)
		local arg = {...}
		local disabler = arg[1] == true

		local depend = registry[self.ref].depend[disabler and 2 or 1]
		local this = registry[self.ref].depend[0]

		for i = (disabler and 2 or 1), table.maxn(arg) do
			local v = arg[i]
			if v then
				if v.__name == "pui::element" then v = {v, true} end
				depend[#depend+1] = v

				local check = function () elemence.dependant(depend, this, disabler) end
				check()

				registry[v[1].ref].callbacks[#registry[v[1].ref].callbacks+1] = check
			end
		end

		return self
	end,

	override = function (self, value)
		local ctx, wctx = registry[self.ref], ragebot.context[ragebot.ref.value]

		if value ~= nil then
			if not ctx.overridden then
				if self.type == "hotkey" then self.value = { ui.get(self.ref) } end
				if ctx.__rage then wctx[self.ref] = self.value else ctx.original = self.value end
			end ctx.overridden = true
			if ctx.__rage then ctx.__ovr_v = value end
			ui_mset(self.ref, value)
		else
			if ctx.overridden then
				local original = ctx.original if ctx.__rage then original, ctx.__ovr_v = wctx[self.ref], nil end
				ui_mset(self.ref, original)
				ctx.overridden = false
			end
		end
	end,
	get_original = function (self)
		if registry[self.ref].overridden then
			if registry[self.ref].__rage then
				return ragebot.context[ragebot.ref.value][self.ref]
			else
				return registry[self.ref].original
			end
		else return self.value end
	end,

	--

	set = function (self, ...)
		if self.type == "color_picker" then
			ui.set(self.ref, unpack(utils.unpack_color(...)) )
			methods_mt.element.invoke(self)
		elseif self.type == "label" then
			local t = utils.format(...)
			ui.set(self.ref, t)
			self.value = t
		else
			ui.set(self.ref, ...)
		end
	end,
	get = function (self, value)
		if value and self.type == "multiselect" then
			return registry[self.ref].options[value] or false
		end
		return ui.get(self.ref)
	end,

	reset = function (self) if registry[self.ref].__init then ui.set(self.ref, registry[self.ref].__init) end end,

	update = function (self, t)
		ui.update(self.ref, t)
		registry[self.ref].__list = t

		local cap = #t-1
		if ui.get(self.ref) > cap then ui.set(self.ref, cap) end
	end,
	get_list = function (self) return registry[self.ref].__list end,

	is_active = function (self)
		return self.value and ui.get(self.hotkey.ref)
	end,
	get_color = function (self)
		if registry[self.ref].__addon then return ui.get(self.color.ref) end
	end,
	set_color = function (self, ...)
		if registry[self.ref].__addon then methods_mt.element.set(self.color, ...) end
	end,
	get_hotkey = function (self)
		if registry[self.ref].__addon then return ui.get(self.hotkey.ref) end
	end,
	set_hotkey = function (self, ...)
		if registry[self.ref].__addon then methods_mt.element.set(self.hotkey, ...) end
	end,

	is_reference = function (self) return registry[self.ref].__ref or false end,
	get_type = function (self) return self.type end,
	get_name = function (self) return self.name end,

	set_visible = function (self, visible)
		ui.set_visible(self.ref, visible)
		if registry[self.ref].__addon then ui.set_visible(self[registry[self.ref].__addon].ref, visible) end
	end,
	set_enabled = function (self, enabled)
		ui.set_enabled(self.ref, enabled)
		if registry[self.ref].__addon then ui.set_enabled(self[registry[self.ref].__addon].ref, enabled) end
	end,

	set_callback = function (self, func, once)
		if once == true then func(self) end
		registry[self.ref].callbacks[#registry[self.ref].callbacks+1] = func
	end,
	unset_callback = function (self, func)
		table.remove(registry[self.ref].callbacks, table.qfind(registry[self.ref].callbacks, func) or 0)
	end,
	invoke = function (self, ...)
		for i = 0, #registry[self.ref].callbacks do registry[self.ref].callbacks[i](self, ...) end
	end,

	set_event = function (self, event, func, condition)
		local slot = registry[self.ref]
		if condition == nil then condition = true end
		local is_cond_fn, latest = type(condition) == "function", nil
		slot.events[func] = function (this)
			local permission if is_cond_fn then permission = condition(this) else permission = this.value == condition end

			local action = permission and client.set_event_callback or client.unset_event_callback
			if latest ~= permission then action(event, func) latest = permission end
		end
		slot.events[func](self)
		slot.callbacks[#slot.callbacks+1] = slot.events[func]
	end,
	unset_event = function (self, event, func)
		client.unset_event_callback(event, func)
		methods_mt.element.unset_callback(self, registry[self.ref].events[func])
		registry[self.ref].events[func] = nil
	end,

	get_location = function (self) return registry[self.ref].tab, registry[self.ref].container end,
}	methods_mt.element.__index = methods_mt.element

methods_mt.group = {
	__name = "pui::group",
	__metatable = false,
	__index = function (self, key) return rawget(methods_mt.group, key) or pui_mt.__index(self, key) end,
	get_location = function (self) return self[1], self[2] end
}

-- #endregion
--

--
-- #region : pui_mt, ragebot and plist handler

do
	local cached = {}
	for k, v in next, elements do
		cached[k] = function (origin, ...)
			local args, group = utils.dispense(k, origin, ...)
			local this = elemence.new( contend(ui["new_".. k], 3, group[1], group[2], unpack(args, 1, args.n < args.req and args.n or args.req)), args.data )

			elemence.features(this, args.misc)
			return this
		end
	end

	pui_mt.__name, pui_mt.__metatable = "pui::basement", false
	pui_mt.__index = function (self, key)
		if not elements[key] then return ui[key] end
		if key == "string" then return elemence.string end

		return cached[key]
	end
end


--#region: ragebot handler

ragebot = {
	ref = pui.reference("RAGE", "Weapon type", "Weapon type"),
	context = {}, cache = {},
	silent = false,
} do
	local previous, cycle_action = ragebot.ref.value, nil
	for i, v in ipairs(weapons) do ragebot.context[v], ragebot.cache[v] = {}, {} end

	local neutral = ui.reference("RAGE", "Aimbot", "Enabled")
	ui.set_callback(neutral, function ()
		if not ragebot.silent then client.delay_call(0, client.fire_event, "pui::adaptive_weapon", ragebot.ref.value, previous) end
		if cycle_action then cycle_action(ragebot.ref.value) end
	end)

	ragebot.cycle = function (fn, mute)
		cycle_action = mute and fn or nil
		ragebot.silent = mute and true or false

		for i, v in ipairs(weapons) do
			ragebot.ref:override(v)
		end

		ragebot.ref:override()
		cycle_action, ragebot.silent = nil, false
	end

	ui.set_callback(ragebot.ref.ref, function (self)
		ragebot.ref.value = ui.get(self)

		if not ragebot.silent and previous ~= ragebot.ref.value then
			for i = 1, #registry[self].callbacks, 1 do registry[self].callbacks[i](ragebot.ref) end
		end

		previous = ragebot.ref.value
	end)

	local memorize = function (self)
		local ctx = ragebot.context[ragebot.ref.value]
		if registry[self.ref].overridden then
			if ctx[self.ref] == nil then
				ctx[self.ref] = self.value
				ui_mset(self.ref, registry[self.ref].__ovr_v)
			end
		else
			if ctx[self.ref] then
				ui_mset(self.ref, ctx[self.ref])
				ctx[self.ref] = nil
			end
		end
	end

	client.set_event_callback("pui::adaptive_weapon", function (cur, prev)
		for k, v in next, registry do
			if v.__rage then memorize(v.self) end
		end
	end)

	ragebot.memorize = function (self) end
end

--#endregion

--#region: plist handler

players = {
	elements = {}, list = {},
} do
	--#region: stuff

	pui.plist = elemence.group("PLAYERS", "Adjustments")
	pui.plist.__plist = true

	local selected = 0
	local refs, slot = {
		list = pui.reference("PLAYERS", "Players", "Player list"),
		reset = pui.reference("PLAYERS", "Players", "Reset all"),
		apply = pui.reference("PLAYERS", "Adjustments", "Apply to all"),
	}, {}

	--#endregion

	--#region: slot metatable

	local slot_mt = {
		__type = "pui::player_slot", __metatable = false,
		__tostring = function (self)
			return string.format("pui::player_slot[%d] of %s", self.idx, methods_mt.element.__tostring(registry[self.ref].self))
		end,
		set = function (self, ...) -- don't mind
			local ctx, value = registry[self.ref], {...}

			local is_colorpicker = ctx.type == "color_picker"
			if is_colorpicker then
				value = utils.unpack_color(...)
			end

			if self.idx == selected then
				ui.set( self.ref, unpack(value) )
				if is_colorpicker then
					methods_mt.element.invoke(ctx.self)
				end
			else
				self.value = is_colorpicker and value or unpack(value)
			end
		end,
		get = function (self, find)
			if find and registry[self.ref].type == "multiselect" then
				return table.qfind(self.value, find) ~= nil
			end

			if registry[self.ref].type ~= "color_picker" then return self.value
			else return unpack(self.value) end
		end,
	}	slot_mt.__index = slot_mt

	--#endregion

	--#region: slots handling stuff

	players.traverse = function (fn) for i, v in ipairs(players.elements) do fn(v) end end

	slot = {
		select = function (idx)
			if not idx then return end
			for i, v in ipairs(players.elements) do
				methods_mt.element.set(v, v[idx].value)
			end
		end,
		add = function (idx)
			if not idx then return end
			for i, v in ipairs(players.elements) do
				local default = ternary(registry[v.ref].__init ~= nil, registry[v.ref].__init, v.value)
				v[idx], players.list[idx] = setmetatable({
					ref = v.ref, idx = idx, value = default
				}, slot_mt), true
			end
		end,
		remove = function (idx)
			if not idx then return end
			for i, v in ipairs(players.elements) do
				v[idx], players.list[idx] = nil, nil
			end
		end,
	}

	players.slot_update = function (self)
		if self[selected] then self[selected].value = self.value
		else slot.add(selected) end
	end

	--#endregion

	--#region: callbacks

	local silent = false
	local update = function (e)
		selected = ui.get(refs.list.ref)

		local new, old = entity.get_players(), players.list
		local me = entity.get_local_player()

		for idx, v in next, old do
			if entity.get_classname(idx) ~= "CCSPlayer" then
				slot.remove(idx)
			end
		end

		for i, idx in ipairs(new) do
			if idx ~= me and not players.list[idx] and entity.get_classname(idx) == "CCSPlayer" then
				slot.add(idx)
			end
		end

		if not silent and not e.value then
			for i = #new, 1, -1 do
				if new[i] ~= me then ui.set(refs.list.ref, new[i]) break end
			end
			client.update_player_list()
			silent = true
		else
			silent = false
		end

		slot.select(selected)
		client.fire_event("pui::plist_update", selected)
	end

	do
		local function once ()
			update{}
			client.unset_event_callback("pre_render", once)
		end
		client.set_event_callback("pre_render", once)
	end
	methods_mt.element.set_callback(refs.list, update, true)
	client.set_event_callback("player_connect_full", update)
	client.set_event_callback("player_disconnect", update)
	client.set_event_callback("player_spawned", update)
	client.set_event_callback("player_spawn", update)
	client.set_event_callback("player_death", update)
	client.set_event_callback("player_team", update)

	--

	methods_mt.element.set_callback(refs.apply, function ()
		players.traverse(function (v)
			for idx, _ in next, players.list do
				v[idx].value = v[selected].value
			end
		end)
	end)
	methods_mt.element.set_callback(refs.reset, function ()
		players.traverse(function (v)
			for idx, _ in next, players.list do
				if idx == selected then
					slot_mt.set(v[idx], registry[v.ref].__init)
				else
					v[idx].value = registry[v.ref].__init
				end
			end
		end)
	end)

	--#endregion
end

--#endregion

-- #endregion
--


-- #endregion -----------------------------------------------------------
--


return setmetatable(pui, pui_mt)