GetPlayerName returns nil if you extrapolate from playerConnecting

If I try to fetch a player’s username in the playerConnecting event. everything works as expected, but if I try to extrapolate code that repeats into a CompilePlayer(src) function, it stops working.

AddEventHandler("playerConnecting", function()
    local Source = source
    print(GetPlayerName(Source)) -- Not_Luna
end)
function CompilePlayer(src)
    local player = {}
    player.source = src
    player.username = GetPlayerName(src)
    -- other player calls here (such as GetPlayerIdentifiers()) also don't work.
    return player
end
AddEventHandler("playerConnecting", function()
    local Source = source
    local player = CompilePlayer(Source)
    print(player.source) -- 65535
    print(player.username) -- nil
end)

if anyone can explain this, and or recommend work arounds. I’m hoping to be able to use the CompilePlayer function as a universal function which can be used both in and out of the playerConnecting event to compile all the player information into one easy table.

You shouldn’t really do that. playerConnecting returns a temporary source, as the player hasn’t received a server slot yet (since they are still connecting, and might drop). playerConnecting returns the player name in the first function argument, so you can use that. The player identifiers native should work as well… have you tried to tonumber() your source in the CompilePlayer() function? Just in case.

Also, check the documentation on how playerConnecting is handled. playerConnecting - Cfx.re Docs

Additionally, you can use the playerJoining event, which triggers after the player receives a definitive server source:

AddEventHandler('playerJoining', function(oldID)
    local src = source -- players definitive server source
    local old = oldID -- player's source from playerConnecting event.
end)
1 Like

I didn’t include the full code, but I understand that the source is temporary. The CompilePlayer functions primary usage has nothing to do with the source, but rather the fact that none of the player data functions that work within the playerConnecting event, work if I try to use them in an extrapolated function, which takes the temporary or permanent source as it’s one and only argument.

Actually, the two main purposes of this function is to combine all the player data into an easy to use table (where player.username and player.identifiers.steam and player.banned are all easily accessible and reliably available and consistent) and also to make DB calls such as fetching preferences, ban state and or reason, and more. Ban related info obviously being the most important data during the connecting event.

I have tried that, it didn’t help unfortunately

I’m not sure the joining event is the best place to be trying to compile player data, as at this point it’s slightly late to be kicking for ban reason (where deferrals are likely better used for this purpose) and if I wanted to pass on any of the compiled player data to the loading screen, such as preferences, it’s definitely too late for that, at least as far as I know.

I think I understand what you’re trying to do @Luna .

I guess an additional, helpful question is:

Between playerconnecting and playerjoining is it possible to defer players from entering your server in both instances, or at LEAST pause the player’s joining so that you can make a decision whether they need to be banned or if they’re authorized to join?

From what it looks like, you’re trying to fully, and positively identify a player before they join, is that correct?

If this is the case, I will say, player names are changeable, however, their steam identifier, in-game identifier, and others, are a lot harder to change (and damn-near impossible to disassociate/reassociate with other identities, hint-hint). That said, you’re given quite a few player ID’s to work with. Is there a reason the one’s provided in playerconnecting aren’t feasible enough?

Lastly, I don’t want to just shift your focus away from your intended initial goal (in case you’re trying to leverage something that you’re not explaining above - e.g. trying to resolve the id to a player name for logging purposes), so one thing you may be able to do is to Get a steam name from a steam ID programmatically, however, this requires connection to the steam ay-pee-eye and probably a few other things AND ISN’T GUARANTEED TO MATCH THE FIVEM NAME (unless other people can vouch that it will).

Anyways, these are my thoughts. Let us know (lettuce snow) what you think!

Heyo,

So, I tried your example code on my (old, opss) server artifacts (v10778) and on new one (v12168) and it works fine for me?

function CompilePlayer(src)
    local player = {}
    player.source = src
    player.username = GetPlayerName(src)
    player.identifiers = GetPlayerIdentifiers(src)
    return player
end
AddEventHandler("playerConnecting", function() -- you should use the passed args here, btw. But it works without them as well.
    local Source = source
    local player = CompilePlayer(Source)
    print(player.source)
    print(player.username)
    for i,k in pairs(player.identifiers) do
        print(k)
    end
end)

I am not exactly sure why it fails for you… maybe you have more code in your actual function that breaks it.

Regarding this… I am not exactly sure why you would even want to compute the player’s whole data from the DB, if they’re not even on the server yet. As you said, they might be rejected for being banned. They might cancel their connection, or remain in some sort of queue and cancel from there.

What I personally did is I only handle the bare necessities in playerConnecting (is the name compliant, is the player banned, is the player allowlisted (if that is active), does the player actually have an account, etc).

The rest is done in playerJoining, which runs as soon as deferrals are completed, and the player starts to actually load the resources (which means you can safely send loading screen data from here as well.)

1 Like

I’d like to explain further, just so you know what the scope is, but I’ll let you know, the issue was actually a debugging “early exit” in case any of my code threw errors, I wouldn’t start joining the server, allowing me to test my code slightly faster. This wasn’t a weird fivem glitch like I initially thought.

TL;DR: FiveM's GetPlayer...() functions don't work after you disconnect the player.

Now, onto what I’m doing: I’m writing a brand new framework, which is likely to remain closed-source, but allows me and any other developers of my server to initialize what is essentially a Player class, which contains all the information about a player. This includes, not only what fivem provides accessible via Player.username, Player.endpoint, etc. but also Player.identifiers is a table which looks like identifiers[type] = identifier. But, this class also exposes database values as well, so you can also call Player.group, Player.banned, or Player.whitelisted. Additionally, if a player has identifiers appear and disappear due to, for example forgetting to open discord on a subsequent connection, their previously known identifiers will be available as well.

Ultimately though, the original issue of this post was that at the beginning of my playerConnecting event, I was using deferal.done(“debugging logins”) to force my game to never hit the loading screen, which resulted in fivem immediately disposing of the player, so none of my code for fetching fivem variables worked when I later called local player = Player(Source) to initialize a player class, because fivem had disposed of that information. The fix being of course, to move the deferal.done call later on in the function, and I believe I failed to realize the issue because when I first started to work on this idea, the first few lines of the event handler were the first few lines of the CompilePlayer function.

Gotcha! Okay, so what you’re looking for is a way to associate players that join with previously established identities. Which requires fiveM player data that already comes supported, you just implemented a debug that was preventing you from utilizing fiveM’s native player id’s.

No problem, and a good idea. Hopefully this topic at least gives people some frame of reference when it comes to gathering player identifiers! Good luck on your project (and I’d love to see progress on this (even if you’re keeping it closed source, and if you’re willing, of course!))

In c# i use:

[EventHandler("playerConnecting")]
private async void onPlayerConnecting([FromSource] Player player, string playerName, dynamic defferals, dynamic setKickReason)
{
     string playerName = player.Name;
}

the source holds the player information on c# so

player.Name

gives the desired name, not sure how that carries over to lua

Also the docs state that the “onPlayerConnecting” sends the name also as my example above

local function OnPlayerConnecting(name, setKickReason, deferrals)
    local player = source

Docs