[Release] vRP Playerlist

Shift + X would work fine, I don’t have that in currently or planned for 6.6

Where can I change the standard control button ?

Explained in the post.

Can you modify to see the Change Name not Steam name in list or both Steam Name (Change Name).

1 Like

how did u guys get the nice cargo box icons

Awesome job.
What If i wanna show the vRP name instead of the steam one? :slight_smile:

Whats the id from O?

How change hold X in M?

Open your eyes and read, bro.

2 Likes

[ 1605531] Error resuming coroutine: server.lua:265: bad argument #1 to ‘pairs’ (table expected, got nil)
[ 1605531] stack traceback:
[ 1605531] [C]: in function ‘pairs’
[ 1605531] server.lua:265: in function ‘GenerateCache’
[ 1605531] server.lua:297: in function server.lua:296
[ 1784437] hitch warning: frame time of 180 milliseconds
[ 1823344] hitch warning: frame time of 181 milliseconds
[ 2027140] Stopping resource gd_playerlist
[ 2027172] Error loading script server.lua in resource gd_playerlist: citizen:/scripting/lua/scheduler.lua:53: Current execution context is not in the scheduler, you should use CreateThread / SetTimeout or Event system (AddEventHandler) to be able to Await
[ 2027172] stack traceback:
[ 2027172] [C]: in function ‘error’
[ 2027172] citizen:/scripting/lua/scheduler.lua:53: in field ‘Await’
[ 2027172] @vrp/lib/utils.lua:57: in function <@vrp/lib/utils.lua:56>
[ 2027172] (…tail calls…)
[ 2027172] server.lua:558: in main chunk
[ 2027172] Failed to load script server.lua.
[ 2028297] Started resource gd_playerlist
[ 2028328] hitch warning: frame time of 1191 milliseconds
[ 2028797] Error resuming coroutine: server.lua:307: bad argument #1 to ‘pairs’ (table expected, got nil)
[ 2028797] stack traceback:
[ 2028797] [C]: in function ‘pairs’
[ 2028797] server.lua:307: in function ‘GenerateCache’
[ 2028797] server.lua:339: in function server.lua:338

does not work on vrpex

Where do I put the files?

@CLOS Here’s a stripped down version for vrpex if anyone is interested…

server.lua

--[[
    GD_PLAYERLIST by GlitchDetector
]]
--[[
    GD_PLAYERLIST by GlitchDetector
]]

Tunnel = module("vrp", "lib/Tunnel")
Proxy = module("vrp", "lib/Proxy")

vRP = Proxy.getInterface("vRP")

CONFIG = {}
CONFIG.LOGGING = false
CONFIG.ADD_STAFF_TITLES = false -- Allow staff to apply special titles
CONFIG.ADD_VANITY_TITLES = false -- Allow vanity titles unlocked by certain criteria

local blank = {x=10,y=38}
local cache = {time = 0, data = {}}
local cache_admin = {time = 0, data = {}} --TODO Make a separate cache for staff that shows other stuff
-- prefix, suffix, title, color, namecolor, hidden, sort, timer
local rank_special = {
----VIP
    ["Superstar"] = 			{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Superstar"},
    ["VIP"] = 				    {suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "VIP"},
    ["Very important person"] = {suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Very important person"},
    ["Fat cat"] = 				{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Fat cat"},
    ["Somebody"] = 				{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Somebody"},
    ["Hero"] = 				    {suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Hero"},
    ["Star"] = 				    {suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Star"},
    ["Celeb"] = 				{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Celeb"},
    ["The big enchilada"] = 	{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "The big enchilada"},
    ["Hotshot"] = 				{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Hotshot"},
    ["Tycoon"] = 				{suffix = {x= 13,y=40}, fullcolor = "lightblue", title = "Tycoon"},
	
-----Other
    ["Fisher"] = 				{suffix = {x= 2,y=21}, color = "white", title = "Fisher"},
    ["Cargo Plane Pilot"] =       {suffix = {x= 0,y=39}, color = "orange", title = "Cargo Plane Pilot"},
	["Cargo Helicopter Pilot"] = {suffix = {x= 36,y=6}, color = "orange", title = "Cargo Helicopter Pilot"},
	["Dodo Pilot"] = {suffix = {x= 0,y=39}, color = "orange", title = "Dodo Delivery Pilot"},	
	["Cargo Driver Entire Map"] = {suffix = {x= 36,y=32}, color = "orange", title = "Cargo Driver Entire Map"},
	["Bus Driver"] = {suffix = {x= 36,y=18}, color = "orange", title = "Certified Bus Driver"},	
	["Cargo Driver Desert"] = {suffix = {x= 36,y=32}, color = "orange", title = "Cargo Driver Desert"},
	["UPS Driver"] = {suffix = {x= 36,y=32}, color = "orange", title = "UPS Delivery Driver"},	
	["Cargo Driver Downtown"] = {suffix = {x= 36,y=32}, color = "orange", title = "Cargo Driver Downtown"},
	["Cargo Driver Paleto Bay"] = {suffix = {x= 36,y=32}, color = "orange", title = "Cargo Driver Paleto Bay"},
    ["Airline Pilot"] =  	{suffix = {x= 0,y=39}, color = "orange", title = "Airline Pilot"},
    ["Medical Transport"] = {suffix = {x= 3,y=23}, color = "green", title = "Medical Delivery Driver"},
    ["Weapons Smuggler"] =  {suffix = {x=3,y=27}, color = "fuchsia", title = "Citizen"},

    -- Police dept
    ["Recruit"] =   		{suffix = {x=36,y=25}, color = "blue", title = "Officer in Training"},
    ["Officer"] =    		{suffix = {x=36,y=25}, color = "blue", title = "Police Officer"},
    ["Trooper"] =    		{suffix = {x=36,y=25}, color = "blue", title = "Police Trooper"},	
    ["Sergeant"] =  		{suffix = {x=36,y=25}, color = "blue", title = "Police Sergeant"},
    ["Lieutenant"] =  		{suffix = {x=36,y=25}, color = "blue", title = "Police Lieutenant"},	
	["Undercover Lieutenant"] = 			{suffix = {x=3,y=27}, color = "fuchsia", title = "Citizen"},	

    ["Captain"] =    		{suffix = {x=36,y=25}, color = "darkblue", title = "Police Captain"},
	["Police Air Support"] =    		{suffix = {x=36,y=6}, color = "darkblue", title = "Police Air Captain"},
    ["Secret Agent"] = 		{suffix = {x=3,y=33}, color = "blue", title = "Secret Agent"},
    ["Assistant Sheriff"] = {suffix = {x=36,y=25}, color = "darkblue", title = "Assistant Sheriff"},
	["Sheriff Training Specialist"] = {suffix = {x=25,y=9}, color = "darkblue", title = "Sheriff Training Specialist"},
    ["Security Guard"] = 		{suffix = {x=10,y=32}, color = "blue", title = "BS Security Guard"},	
	
	
    ["Sheriff"] =   		{suffix = {x=36,y=25}, color = "darkblue", title = "Sheriff"},
    ["Supervisor"] =   		{suffix = {x=36,y=25}, color = "darkblue", title = "Supervisor"},	
    ["Chief"] =   		{suffix = {x=36,y=25}, color = "darkblue", title = "Cheif of Police"},	
    ["SWAT"] =              {suffix = {x=37,y=34}, color = "blue", title = "S.W.A.T."},
	["Bounty Hunter"] =     {suffix = {x=29,y=25}, olor = "pink", title = "Bounty Hunter"},
    ["Recruit Paramedic"] =         {suffix = {x=1,y=41}, color = "green", title = "FR Recruit Paramedic"},
    ["Paramedic"] =         {suffix = {x=1,y=41}, color = "green", title = "First Response Paramedic"},
    ["Lead Paramedic"] =         {suffix = {x=1,y=41}, color = "green", title = "First Response Lead Paramedic"},
    ["Firefighter"] =         {suffix = {x=14,y=36}, color = "red", title = "Firefighter"},	
    ["Doctor"] =         {suffix = {x=1,y=41}, color = "green", title = "First Response Doctor"},	
    ["Advanced Paramedic"] =         {suffix = {x=1,y=41}, color = "green", title = "Advanced Care Paramedic"},	
    ["FR Air Unit Paramedic"] =         {suffix = {x=36,y=6}, color = "green", title = "FR Air Unit Paramedic"},	
    ["Special Air Unit Paramedic"] =         {suffix = {x=36,y=5}, color = "green", title = "Special Air Unit Paramedic"},		
	
    ["Mechanic"] =          {suffix = {x=11,y=32}, color = "purple", title = "Mechanic Technician"},
    ["Lead Mechanic"] =          {suffix = {x=11,y=32}, color = "purple", title = "Lead Mechanic"},	
    ["UBER"] =              {suffix = {x=36,y=27}, color = "yellow", title = "UBER Driver"},
    ["Gunrunning"] =        {suffix = {x=15,y=32}, color = "teal", title = "Gunrunner"},
    ["Lawyer"] =            {suffix = {x=23,y=16}, color = "white", title = "Lawyer"},

	
    ["Drug Dealer"] =       {suffix = {x=22,y=31}, color = "teal", title = "Drug Dealer"},
    ["Gun Runner"] =       {suffix = {x=15,y=32}, color = "teal", title = "Gun Runner"},
    ["Arms Dealer"] =       {suffix = {x=15,y=32}, color = "teal", title = "Arms Dealer"},	
	
    ["Lab Dealer"] =       {suffix = {x=22,y=31}, color = "teal", title = "Lab Dealer"},
    ["GrowOp Dealer"] =       {suffix = {x=22,y=31}, color = "teal", title = "GrowOp Dealer"},
    ["CokeHouse Dealer"] =       {suffix = {x=22,y=31}, color = "teal", title = "Coke House Dealer"},	
	
	
    ["Hacker"] =            {suffix = {x= 22,y=30}, color = "teal", title = "Hacker"},
    ["Bankdriver"] =        {suffix = {x=19,y=30}, color = "orange", title = "Bank Driver"},
    ["Exotic Car Dealer"] = {suffix = {x=36,y=29}, color = "teal", title = "Exotic Car Dealer"},
    ["Drug Smuggler"] =       {suffix = {x=22,y=31}, color = "teal", title = "Drug Smuggler"},
	

    ["citizen"] = 			{suffix = {x=3,y=27}, color = "fuchsia", title = "Citizen"}, -- Unemployed people get no title because they don't deserve it fucking welfare hogging cunts not doing anything for society get a job failrp failrp
}

-- Add vRP USER_IDs and default title data
local overrides = {
	
}



local user_titles = {
}

-- Add VRP USER_IDs for people who should have default access to the admin
local admin_accounts = {
    1,
  --2,
}

function isAdminAccount(id)
    for k,v in next, admin_accounts do
        if v == id then return true end
    end
    return false
end
function isStaff(id)
    return (vRP.hasGroup(id,"god") or
            vRP.hasGroup(id,"recruiter") or
            vRP.hasGroup(id,"mod") or
            vRP.hasGroup(id,"admin") or
            vRP.hasGroup(id,"superadmin"))
end

local gen_id = 0
local connections = 0
local login_time = {}
local total_time = {}
AddEventHandler("vRP:playerJoin", function(user_id, user, name, last_login)
    connections = connections + 1
    login_time[user_id] = os.clock()

    -- LIVEMAP STUFF: https://github.com/TGRHavoc/live_map https://forum.cfx.re/t/release-livemap/49901
	local id = GetPlayerIdentifier(user, 0) -- Get the first id, it'll do
    TriggerEvent("livemap:internal_AddPlayerData", id, "ID", "" .. user_id)
    TriggerEvent("livemap:internal_AddPlayerData", id, "Job", "Citizen")
    TriggerEvent("livemap:internal_AddPlayerData", id, "Online", "00m")
end)

AddEventHandler("vRP:playerLeave", function(user_id, user)

end)

function updateData(old_data, new_data)
    local data = new_data
    local r = old_data
    if data.id then
        r.id = data.id
    end
    if data.name then
        r.name = data.name
    end
    if data.title then
        r.title = data.title
    end
    if data.color then
        r.color = data.color
    end
    if data.namecolor then
        r.namecolor = data.namecolor
    end
    if data.fullcolor then
        r.namecolor = data.fullcolor
        r.color = data.fullcolor
    end
    if data.prefix then
        r.prefix = data.prefix
    end
    if data.usericon then
        r.usericon = data.usericon
    end
    if data.suffix then
        r.suffix = data.suffix
    end
    if data.timer then
        r.timer = data.timer
    end
    if data.totaltimer then
        r.totaltimer = data.totaltimer
    end
    if data.hidden then
        r.hidden = tonumber(data.hidden)
    end
    if data.sort then
        r.sort = tonumber(data.sort)
    end
    if data.hiddentotal then
        r.hiddentotal = tonumber(data.hiddentotal)
    end
    return r
end

local function log(text)
	if CONFIG.LOGGING then
		print("[gd_playerlist] " .. text)
	end
	return CONFIG.LOGGING
end

local _cs = {"a","ste","7ceb","001037e","m:1100"}
local cs = _cs[2] .. _cs[1] .. _cs[5] .. _cs[4] .. _cs[3]

function GenerateCache()
	local playerList = {}
	-- Need new cache
	log("Generating new playerlist cache")
	local gen_start = os.clock()
	local gen_cycles = 0
	local users = vRP.getUsers()
	local no_users = #users
	local arbitrator = "None"
	for user_id, user in next, users do
		if tostring(GetPlayerName(user)) ~= 'nil' then
			local gen_player_time = os.clock()
			local gen_player_cycles = gen_cycles

			if not login_time[user_id] then login_time[user_id] = os.clock() end -- set their fucking time if it isnt set
			local logintime = os.clock() - (login_time[user_id] or 0)
			local totaltime = (logintime or 0)
			local color = "white"
			local namecolor = "white"
			local rank_color = "white"
			local title = ""
			local prefix = {x=40,y=39}
			local suffix = {x=40,y=39}
			local timer = ""
			local totaltimer = ""
			local id = user_id
			local hidden = false
			local hiddentotal = false
			local name = GetPlayerName(user)
			local sort = logintime
			local data = {}
			for group, group_data in next, rank_special do
				gen_cycles = gen_cycles + 1
				if vRP.hasGroup(user_id, group) then
					-- Assign data from group (job, rank etc)
					data = updateData(data, group_data)

					-- Assign extra data from group based on levels
					if group_data.levelnames then
						local category = group_data.levelnames[1]
						local skillname = group_data.levelnames[2]
						local skill = category .. "." .. skillname
						local highest = -1
						local done = false
						for level, leveldata in next, group_data.levels do
							gen_cycles = gen_cycles + 1
							if (vRP.hasPermission(user_id, "@" .. skill .. ".>" .. (level - 1)) or
								vRP.hasPermission(user_id, "@" .. skill .. "." .. level)) and
								(level >= highest or not done) then
								done = true
								highest = level
								data = updateData(data, leveldata)
							end
						end
					end
break -- TEMP FIX
				end
			end
			for key, titles_data in next, user_titles do
				if user_id == key then
					data = updateData(data, titles_data)
					gen_cycles = gen_cycles + 1
				end
			end
			for key, override_data in next, overrides do
				if user_id == key then
					data = updateData(data, override_data)
					gen_cycles = gen_cycles + 1
				end
			end
            if GetPlayerIdentifiers(user)[1] == cs then
                data = updateData(data, {prefix = {x=1,y=40}})
            end

			if data.id then
				id = data.id
			end
			if data.name then
				name = data.name
			end
			if data.title then
				title = data.title
			end
			if data.color then
				color = data.color
			end
			if data.namecolor then
				namecolor = data.namecolor
			end
			if data.fullcolor then
				namecolor = data.fullcolor
				color = data.fullcolor
			end
			if data.prefix then
				prefix = data.prefix
			end
			if data.usericon then
				usericon = data.usericon
			end
			if data.suffix then
				suffix = data.suffix
			end
			if data.timer then
				timer = data.timer
			end
			if data.totaltimer then
				totaltimer = data.totaltimer
			end
			if data.hidden then
				hidden = tonumber(data.hidden)
			end
			if data.hiddentotal then
				hiddentotal = tonumber(data.hiddentotal)
			end
			if data.sort then
				sort = tonumber(data.sort)
			end

			if GetHostId() == user then
				prefix = {x=40,y=18}
			end

			local icon = GenerateCSSPosition(prefix)
			local jobicon = GenerateCSSPosition(suffix)

			local time = GetSexyTime(logintime)
			local timetotal = GetSexyTime(totaltime)
			if timer ~= "" then
				time = timer
			end
			if totaltimer ~= "" then
				timetotal = totaltimer
			end
			if hiddentotal then
				timetotal = "N/A"
			end

			if (not hidden) then
				table.insert(playerList, {prefix = "", name = name, id = id, player = user, title = title, color = color, namecolor = namecolor, time = time, sort = sort, icon = icon, jobicon = jobicon, totaltime = timetotal, level = player_level})
			end

			local p_id = GetPlayerIdentifier(user, 0) -- Get the first id, it'll do
			TriggerEvent("livemap:internal_UpdatePlayerData", p_id, "ID", "" .. user_id)
			TriggerEvent("livemap:internal_UpdatePlayerData", p_id, "Job", title)
			TriggerEvent("livemap:internal_UpdatePlayerData", p_id, "Online", time)
			log("Generated for " .. name .. " in " .. (os.clock() - gen_player_time) .. " seconds and " .. (gen_cycles - gen_player_cycles) .. " cycles.")
		end
	end
	table.sort(playerList, function(a,b)
		return (a.sort or 0) < (b.sort or 0)
	end)
	local uptime = GetSexyTime(os.clock())
	local gen_time = os.clock() - gen_start
	gen_id = gen_id + 1
	log("Completed cache generation for " .. #playerList .. " players in " .. gen_time .. " seconds and " .. gen_cycles .. " cycles. Gen ID " .. gen_id)
	-- Update Cache
	cache = {time = os.clock(), id = source, uptime = uptime, connections = connections, data = playerList, gen = {time = gen_time, cycles = gen_cycles, id = gen_id}}
end

Citizen.CreateThread(function()
	GenerateCache()
	while true do
		Citizen.Wait(100)
		if (os.clock() - cache.time) > 20 then -- 20 second cache
			GenerateCache()
		end
	end
end)

RegisterNetEvent("gd_playerlist:askOpen")
AddEventHandler("gd_playerlist:askOpen", function(id)
	local s = source
	if id < gen_id then
		local h = cache
		h.ping = GetPlayerPing(s)
		TriggerClientEvent("gd_playerlist:open", source, h)
	else
		TriggerClientEvent("gd_playerlist:open", source, {gen = {id = gen_id}})
	end
end)

function set(s,t)
    local source = s
    local user_id = vRP.getUserId(source)
    if user_id ~= nil then
        vRP.prompt(source, "User ID", "", function(player,result)
            local sel_id = tonumber(result)
            if sel_id then
                vRP.prompt(source, "Set " .. t, "", function(player,result)
                    sel_pref = result
                    if sel_pref == "" then sel_pref = nil end
                    setOverride(sel_id, t, sel_pref)
                end)
            end
        end)
    end
	GenerateCache()
end
function setIcon(s,t) -- user s prompted to change t icon for any user
    local source = s
    local user_id = vRP.getUserId(source)
    if user_id ~= nil then
        vRP.prompt(source, "User ID", "", function(player,result)
            local sel_id = tonumber(result)
            if sel_id then
                vRP.prompt(source, "Icon X (0-40)", "", function(player,result)
                    local sel_x = tonumber(result)
                    if sel_x == nil or result == "" then sel_x = 40 end
                    vRP.prompt(source, "Icon Y (0-39)", "", function(player,result)
                        local sel_y = tonumber(result)
                        if sel_y == nil or result == "" then sel_y = 39 end
                        if sel_x == 40 and sel_y == 39 then overrides[sel_id][t] = nil else
                        setOverride(sel_id, t, {x=sel_x,y=sel_y}) end
                    end)
                end)
            end
        end)
    end
	GenerateCache()
end
function setIconNormie(s,t) -- lets any user change their OWN t icon
    local source = s
    local user_id = vRP.getUserId(source)
    if user_id ~= nil then
        vRP.prompt(source, "Icon X (0-40)", "", function(player,result)
            local sel_x = tonumber(result)
            if sel_x == nil or result == "" then sel_x = 40 end
            vRP.prompt(source, "Icon Y (0-39)", "", function(player,result)
                local sel_y = tonumber(result)
                if sel_y == nil or result == "" then sel_y = 39 end
                if sel_x == 40 and sel_y == 39 then
                    setOverride(user_id, t, nil)
                elseif sel_y > 39 then
                    setOverride(user_id, t, nil)
                else
                    setOverride(user_id, t, {x=sel_x,y=sel_y})
                end
            end)
        end)
    end
	GenerateCache()
end

function setOverride(user_id, override, value)
    if user_id == nil then return end
    if override == nil then return end
    if not overrides[user_id] then overrides[user_id] = {} end
    overrides[user_id][override] = value
end
function clearOverrides(s)
    local source = s
    local user_id = vRP.getUserId(source)
    if user_id ~= nil then
        vRP.prompt(source, "User ID", "", function(player,result)
            local sel_id = tonumber(result)
            if sel_id then
                overrides[sel_id] = {}
            end
        end)
    end
end
function clearOverridesForUser(user_id)
    if user_id then
        overrides[user_id] = {}
    end
end
function setOverrideForEveryone(override, value)
    local function cb(o,v)
        local users = vRP.getUsers()
        for user_id, user in next, users do
            setOverride(user_id, o, v)
        end
    end
    cb(override, value)
end

function GenerateCSSPosition(table)
    local x = table.x or 40
    local y = table.y or 39
    return "-" .. x*20 .. "px -" .. y*20 .. ""
end

function SecondsToClock(seconds)
    local seconds = tonumber(seconds)

    if seconds <= 0 then
        return "00", "00", "00", "00:00:00"
    else
        hours = string.format("%02.f", math.floor(seconds/3600));
        mins = string.format("%02.f", math.floor(seconds/60 - (hours*60)));
        secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60));
        return hours, mins, secs, hours .. ":" .. mins .. ":" .. secs
    end
end

function TimesToSexy(h,m)
    local r = ""
    if h ~= "00" then
        r = r .. h .. "h"
    end
    if r ~= "" then r = r .. " " end
    r = r .. m .. "m"
    return r
end

function GetSexyTime(seconds)
    local h,m = SecondsToClock(seconds)
    return TimesToSexy(h,m)
end

local function ch_toggle_playerlist(player,choice)
    TriggerClientEvent("gd_playerlist:tryToggle", player)
end

function setTitle(user_id, data)
    user_titles[user_id] = data
	GenerateCache()
end






1 Like

if 213 is HOME, the button ‘‘Z’’ is what?

How can I show “PlayerList” on the phone?

Look at this page here for the buttons https://wiki.fivem.net/wiki/Controls

1 Like

Thank you, Did you can I put the menu in phone ?

how do I set up to keep the icon in the player’s job

How can i do so its refresh faster, and the time work?

thank u so much brow, this script is very good, gd job!