Help with name changing script

Hello to whomever it may concern,

I’m hoping to be able to tackle development in this game head on. I do have a sort of intermediate knowledge of multiple languages, especially Lua so I should be ok but may need to ask further questions…

I was hoping that someone could point me in the right direction to make a script that allows you to type /name in chat followed by the name you wish to use, and it would change your name on the up arrow user list, as well as in chat and above your head.

All I need is a level headed and patient person to send me over some links to certain events/functions that I may need, thank you!

server script

local customnames = {}

RegisterCommand("changename", function(source, args)

	if not args[2] then
		print("Command requires two arguements. /changename <firstname> <lastname>")
		return
	end
	
	local serverID = source
	local fullname = args[1] .. ' ' .. args[2]
	
	customnames[serverID] = fullname
	TriggerClientEvent("namechange", -1, customnames)
	
end, false)

RegisterServerEvent("getcustomnames")
AddEventHandler("getcustomnames", function(source)
     TriggerClientEvent("namechange", source, customnames)
end)

client script

local customnames = {}

Citizen.CreateThread(function()
	while not NetworkIsPlayerActive(PlayerId()) do
		Citizen.Wait(0)
	end
	TriggerServerEvent("getcustomnames")
end)

RegisterNetEvent("namechange")
AddEventHandler("namechange", function(names)

	customnames = names

end)

function GetCustomNames()
	return customnames
end

GetCustomNames() can be an export function set in your __resource.lua file which other resources like a modified scoreboard resource would pickup and display instead of steam or account name.

exports {"GetCustomNames"}

You can then just copy the existing scoreboard resource from [system] and name the copied folder to customscoreboard and have that start in your server.cfg instead of scoreboard. You would modify the scoreboard.lua file to look like below and it will pickup the custom names if they exist, else it would use the default steam or account name.

local listOn = false

Citizen.CreateThread(function()
    listOn = false
    while true do
        Wait(0)

        if IsControlPressed(0, 27)--[[ INPUT_PHONE ]] then
            if not listOn then
                local players = {}
				local servernames = exports.customnames:GetCustomNames()
                ptable = GetPlayers()
                for _, i in ipairs(ptable) do
                    local wantedLevel = GetPlayerWantedLevel(i)
                    r, g, b = GetPlayerRgbColour(i)
                    local serverID = GetPlayerServerId(i)
					local playerName = servernames[serverID]
					if not playerName then
						playerName = sanitize(GetPlayerName(i))
					end
					table.insert(players, 
                    '<tr style=\"color: rgb(' .. r .. ', ' .. g .. ', ' .. b .. ')\"><td>' .. serverID .. '</td><td>' .. playerName .. '</td><td>' .. (wantedLevel and wantedLevel or tostring(0)) .. '</td></tr>'
                    )
                end
                
                SendNUIMessage({ text = table.concat(players) })

                listOn = true
                while listOn do
                    Wait(0)
                    if(IsControlPressed(0, 27) == false) then
                        listOn = false
                        SendNUIMessage({
                            meta = 'close'
                        })
                        break
                    end
                end
            end
        end
    end
end)

function GetPlayers()
    local players = {}

    for i = 0, 31 do
        if NetworkIsPlayerActive(i) then
            table.insert(players, i)
        end
    end

    return players
end

function sanitize(txt)
    local replacements = {
        ['&' ] = '&amp;', 
        ['<' ] = '&lt;', 
        ['>' ] = '&gt;', 
        ['\n'] = '<br/>'
    }
    return txt
        :gsub('[&<>\n]', replacements)
        :gsub(' +', function(s) return ' '..('&nbsp;'):rep(#s-1) end)
end

I consider this a hack really, you should explore using a database for persistence and have it save all the character data.

2 Likes
InvokeNative: execution failed: Argument at index 1 was null.
Error running system event handling function for resource name-changer: citizen:/scripting/lua/scheduler.lua:41: Failed to execute thread: Execution of native 000000002f7a49e6 in script host failed.
stack traceback:
        [C]: in upvalue '_in'
        citizen:/scripting/lua/natives_server.lua:349: in function 'TriggerClientEventInternal'
        (...tail calls...)
        server.lua:22: in upvalue 'handler'
        citizen:/scripting/lua/scheduler.lua:175: in function <citizen:/scripting/lua/scheduler.lua:174>
stack traceback:
        [C]: in function 'error'
        citizen:/scripting/lua/scheduler.lua:41: in field 'CreateThreadNow'
        citizen:/scripting/lua/scheduler.lua:174: in function <citizen:/scripting/lua/scheduler.lua:138>

Returns in the server console when I join :confused:

Also, I can’t seem to get the scoreboard to work and actually show up when I press UP

@123LladdCae - My apologies, I didn’t include the edit you also need to make in your new copy of the scoreboard resource. Go into the html folder and edit the scoreboard.html file to look like this and it should work fine if your new scoreboard resource is named customscoreboard. See in the <link tags how the href needs to have your new resource name rather than the original scoreboard.

<html>
	<head>
		<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
		<script src="listener.js" type="text/javascript"></script>
		<link rel="stylesheet" href="nui://customscoreboard/html/reset.css">
        <link rel="stylesheet" href="nui://customscoreboard/html/style.css">
	</head>
	<body>
		<div style="display: none;" id="wrap">
			<table id="ptbl" width="100%">
			</table>
		</div>
	</body>
</html>
1 Like

ooh thank you, i’ll test it out in a second.

I’d usually complain with being spoon-fed code, but seen as this is my first project I can at least now look at this and learn from it, try to understand what everything does. So, thank you so very much for your help mate and for being so friendly… I know it’s rare to find friendly people in these sites haha <3

Yeah, so I just did the changes you said and i’m still getting the problem with the error in the console, aswell as the scoreboard not actually showing, up arrow does literally nothing

This was the same error I had before I edited the customscoreboard/html/scoreboard.html file to the above and now everything works fine.

In server.cfg did you?

#start scoreboard
start customnames
start customscoreboard

In your customnames __resource.lua does it look like this?

resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937'

server_scripts {"server.lua"}

client_scripts {"client.lua"}

exports {"GetCustomNames"}

If not working you should stop customscoreboard and start scoreboard and check to see if it will display again. If it does you have a problem inside your customscoreboard files and might want to start over again.

I fixed it just as you sent that… I realised I had my resource named something other than ‘customnames’ haha woopsies… I got it now though, it all seems to be working. Now to make it change my name in chat, would I just hook into when the client sends a chat message, and change the format? I.e. change the author’s name to the variable. And then also to change the name above someone’s head, use the gamertag stuff found here ?

Yes for the gamer tag stuff if you’re using that.

You have this server event bring triggered when a chat message is entered in resources/[system]/chat/cl_chat.lua

TriggerServerEvent('_chat:messageEntered', GetPlayerName(id), { r, g, b }, data.message)

The GetPlayerName(id) is bring read as ‘author’ in the server event. You would need to pass your custom name there instead if it exists, else you would pass the GetPlayerName(id). This would follow similar process as in the customscoreboard changes where it uses the export to bring in the table and then uses the value if it exists in the table.

I’m not fond of editing system resources so again I would suggest that you make a complete copy of chat and call it customchat. Then modify that instead and don’t start the default chat in your server.cfg. This gives you an easy way to revert back to default to see if you created an issue or not.

    if data.message:sub(1, 1) == '/' then
      ExecuteCommand(data.message:sub(2))
    else
      ptable = GetPlayers()
      for _, i in ipairs(ptable) do
      local servernames = exports.customnames:GetCustomNames()
      local serverID = GetPlayerServerId(i)
      local playerName = servernames[serverID]
      if not playerName then
        playerName = sanitize(GetPlayerName(i))
      end
      TriggerServerEvent('_chat:messageEntered', playerName, { r, g, b }, data.message)
    end
    end
  end

So, I definitely did this wrong haha

There are no errors in client console, server console or the CitizenFX.log file… My keyboard just stop working for in-game stuff. Almost all buttons are rendered useless.

You’d also need to include the entire sanitize(GetPlayerName(i)) function to handle that.

This could also be a result of underlying files in the chat resource needing reference changes to reflect a new resource name similar to how you edited the tags in the customscoreboard resource.

Looks like you have three “post” lines in resources[system]\chat\html\App.js where the URL would need to reflect your new resource name. There could be more, I haven’t played around with default chat much.

looks to be all working! Yay!!

Ok, so I did testing on my own and it all worked but when I invited a friend to my server, it is now sending the messages twice. Once from me, once from him. And also, I may need a bit more help with the playernames above heads…

I really apologise for continuing the post, I had originally thought it was all done. I attempted making my own customplayernames and changing something, but it definitely didn’t work

So it sounds like this is happening twice.

TriggerServerEvent('_chat:messageEntered',

Silly question but did you do this in your server.cfg to make sure you don’t have two chat resources running?

#start chat
start customchat

Yeah I did, that isn’t the issue. Basically, what it’s doing is sending the message from every single client.

So if me and my friend are on the server, and I type ‘Hello’ it would look like this:

Kye Jones: Hello
Fowler: Hello

I think I see your issue if you’re using the snipplet in the above post. Sorry I didn’t give that a proper review when you originally sent it and instead just assumed you were missing the sanitize(GetPlayerName(i)) function.

The issue you have is happening partially because you have the “end” for you for _, i in ipairs(ptable) after the TriggerServerEvent statment. This causes it to TriggerServer on every iteration of that loop. You can move the above the TriggerServerEvent statement but that will not solve your problem completely. Try this:

RegisterNUICallback('chatResult', function(data, cb)
  chatInputActive = false
  SetNuiFocus(false)

  if not data.canceled then
    local id = PlayerId()
	local servernames = exports.customnames:GetCustomNames()
	local playerName = servernames[id]
	if not playerName then
		playerName = GetPlayerName(id)
	end

    --deprecated
    local r, g, b = 0, 0x99, 255

    if data.message:sub(1, 1) == '/' then
      ExecuteCommand(data.message:sub(2))
    else
      TriggerServerEvent('_chat:messageEntered', playerName, { r, g, b }, data.message)
    end
  end

  cb('ok')
end)

I’ll test that later when I can, but thank you again. Honestly, you’re an absolute life saver mate! For my absolute final question, can I please get some assistance with the playernames?

PM me on playernames when you’re ready. I’ll need to spend a bit more time on this one since I’ve always disabled it on every server I’ve developed.

Ah alright, no problem. Will do! Again, thank you! :slight_smile: