[SOLVED] GetPlayerPed() returning 0

Heya,
I don’t usually like asking for help as I’m always worried it’ll be something really stupid so I usually prefer to figure it out by myself first, but I just cannot seem to fix this.

Long story short, I’m making a /use command for people tu use items in their inventory, this command should prompt a message in chat, perform a custom action and play an animation.

I set up my own animation handler as I find “TaskPlayAnim” to be a bit fiddly and I wanted to be able to call animations client side. I set up the whole thing and it worked fine until I got a second player on to test it, and that’s when I realised that I’d been calling the player as “GetPlayerPed(-1)” throughout the whole script, so naturally the animation played for everyone even if only one person used /use.

So I tried to fix this, and I thought it’d be an easy fix.
Yet I can’t seem to GetPlayerPed() to not return 0 whatever I put into it.
I’ve stored the playerid in a variable that I called “player” and that works, it returns 2 same as what I have in the in-game player list for me. But when I input it into “GetPlayerPed(player)” it just returns 0…

usecmd.lua (server script)

ESX = nil

TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
print("esx:getSharedObject ran successfully, ESX")

-- USE COMMAND (/use item_name) Outcome: Play appropriate animation, show message and apply effects (if any)!
TriggerEvent('es:addCommand', 'use', function(source, args, user)

	if args[1] ~= nil then		-- Make sure that there is a word after "/use"
		local itemname = args[1];
		local pname = GetPlayerName(source);
		local pedid = GetPlayerPed(source);
		local xPlayer = ESX.GetPlayerFromId(source);
		local sourceItem = xPlayer.getInventoryItem(itemname);
		print("Received command request '/use'! Set pname to: " .. pname .. " and 'pedid' to " .. pedid);
		
		if (sourceItem.count - 1) >= 0 then -- Make sure the player has enough of the item to use
		
			xPlayer.removeInventoryItem(itemname, 1)
			
			-- BEER ITEM --
			if itemname  == 'beer' then
				local dict = "amb@code_human_wander_drinking@beer@male@idle_a";
				local name = "idle_a";
				local prop = "prop_amb_beer_bottle";
				local propX = 0.145;
				local propY = 0.07;
				local propZ = -0.055;
				local propRotX = -80.0;
				local propRotY = 0.0;
				local propRotZ = 0.0;
				local shouldLoop = true;
				local duration = -1;
				local dropOnEnd = false;
			
				TriggerClientEvent("sendProximityMessageMe", -1, source, pname, "drank a beer.")
				TriggerClientEvent("BRPC:PlayAnim", -1, source, pedid, dict, name, prop, propX, propY, propZ, propRotX, propRotY, propRotZ, shouldLoop, duration, dropOnEnd)
				TriggerClientEvent('Radiant_Drunk:GetDrunk', -1, 2) -- I edited the Radiant_Drunk script to have a BAC level and a /blow command that returns said BAC.
			end
		else
			TriggerClientEvent('BRPC:NoItemError', -1)
		end
	else
		TriggerClientEvent('BRPC:InvalidItemName', -1)
	end
end)

animhandler.lua (client script)

ESX                 = nil;
local player		= nil;
local ped			= nil;
local hasAnimated	= false;
local isAnimating	= false;
local shouldLoop	= false;
local animDict		= nil;
local animName		= nil;
local heldProp		= nil;
local previousProp	= nil;
local animFlag		= 50;
local duration		= -1;

Citizen.CreateThread(function()
	while true do
		Citizen.Wait(0);
		while ESX == nil do
			TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end);
		end
		
		
		Citizen.Wait(0);
		if isAnimating then
			if ped ~= nil then
				SetPedCanHeadIk(ped, false);
				if not hasAnimated then
					RequestAnimDict(animDict)
					while(not HasAnimDictLoaded(animDict)) do Citizen.Wait(0) end
					
					Citizen.Wait(0);
					TaskPlayAnim(ped, animDict, animName, 2.0, 2.0, duration, animFlag, 1, false, false, false);
					print("Animating...");
					print("Animation Dictionary: " .. animDict);
					print("Animation Name: " .. animName);
					print("Animating for: " ..  ped);
					hasAnimated = true;
				end
			end
		end
		
		Citizen.Wait(0);
		if IsControlPressed(0, 25) or IsControlPressed(0, 24) or IsControlPressed(0, 140) or IsControlPressed(0, 141) or IsControlPressed(0, 142) or IsControlPressed(0, 263) or IsControlPressed(0, 264) or IsControlPressed(0, 21) or IsControlPressed(0, 16) or IsControlPressed(0, 17) or IsControlPressed(0, 37) then -- If any of the attack inputs, aiming or the sprint key are pressed
			if isAnimating == true then
				print("Trying to aim a weapon, clearing animation...");
				ClearPedTasksImmediately(ped);
				isAnimating = false;
				hasAnimated = false;
				animDict = nil;
				animName = nil;
				SetPedCanHeadIk(ped, true);
				TriggerEvent('BRPC:AnimDropProp', -1);
			end
		end
	end
	
end)

RegisterNetEvent("BRPC:PlayAnim")
AddEventHandler("BRPC:PlayAnim", function(id, pedid, dict, name, prop, propX, propY, propZ, propRotX, propRotY, propRotZ, loop, dur, dropOnEnd)
	print("Received call for BRPC:PlayAnim event!");
	isAnimating = false; -- Reset isAnimating to false
	
	-- Get/Set the variables
	animDict = dict;
	animName = name;
	shouldLoop = loop;
	animRate = loopSpd;
	duration = dur;
	player = id;
	ped = pedid;
	print("Set 'player' variable to: " .. player);
	print("Set 'ped' variable to: " .. ped);
	
	ClearPedTasksImmediately(ped); -- Clear any prior animations or actions
	
	if shouldLoop then
		animFlag = 51;
	else
		animFlag = 50;
	end
	
	if animDict ~= nil and animName ~= nil then
		isAnimating = true;
		hasAnimated = false;
		print("Set 'isAnimating' to 'true' and 'hasAnimated' to 'false'!");
	end
	
	if prop ~= nil then
		TriggerEvent('BRPC:AnimDropProp', -1);
		heldProp = CreateObject(GetHashKey(prop), 0, 0, 0 ,true, true, true);
		AttachEntityToEntity(heldProp, ped, GetPedBoneIndex(ped, 57005), propX, propY, propZ, propRotX, propRotY, propRotZ, true, true, false, true, 1, true);
	end
	
	if duration ~= -1 and dropOnEnd then
		Citizen.Wait(duration);
		TriggerEvent('BRPC:AnimDropProp', -1);
	end
end)

-- Obsolete
RegisterNetEvent("BRPC:AnimLoopTimer")
AddEventHandler("BRPC:AnimLoopTimer", function()
	print("Received call for BRPC:AnimLoopTimer event!");
	if hasAnimated then
		Citizen.Wait(animRate);
		hasAnimated = false;
	end
end)
-- End of Obsolete

-- Drops the spawned prop
RegisterNetEvent("BRPC:AnimDropProp")
AddEventHandler("BRPC:AnimDropProp", function()
	print("Received call for BRPC:AnimDropProp event!");
		if heldProp ~= nil then
			previousProp = heldProp
			DetachEntity(heldProp, false, false)
			Citizen.Wait(500)
			DeleteEntity(heldProp)
			heldProp = nil
		end
		if previousProp ~= nil then
			Citizen.Wait(0)
			DeleteEntity(previousProp)
		end
end)

Not sure but i think the function GetPlayerPed only can be use by clientside resource, you have to think the ped is like a graphic model in memory, there are a copy of it in each client connected at your server and the server dont have that information because there are storage at memory of each client.

you should throw a clientevent to the client who need do something with his ped.

-- serverside
TriggerClientEvent('BRPC:do_something_with_ped', [id_of_the_client])

--clientside
RegisterNetEvent('BRPC:do_something_with_my_ped')
AddEventHandler('BRPC:do_something_with_my_ped', function()
local ped = GetPlayerPed(-1);
//Do stuff
end)

Yeah, that’s originally what I thought too (that it could only work clientside) but I used to have the function in animhandler.lua which is a client script :confused:

You have to get and use it in clientside, the server dont have the info about playerpeds, try to get the ID of that player (serverside) and throw the clientside event on him

TriggerClientEvent('BRPC:do_something_with_ped', source) -- source is the id of the player who used the command

-clientside
--only that player will execute this
RegisterNetEvent('BRPC:do_something_with_my_ped')
AddEventHandler('BRPC:do_something_with_my_ped', function()
local ped = GetPlayerPed(-1);
//Do stuff
end)

with clientside i mean client script so, you have to use it in a client script

Like I said, that’s what it used to be, that also returned 0 which is why I moved it server side. But if you look at the client script where it now says:

RegisterNetEvent("BRPC:PlayAnim")
AddEventHandler("BRPC:PlayAnim", function(id, pedid, dict, name, prop, propX, propY, propZ, propRotX, propRotY, propRotZ, loop, dur, dropOnEnd)
	print("Received call for BRPC:PlayAnim event!");
	isAnimating = false; -- Reset isAnimating to false
	
	-- Get/Set the variables
	animDict = dict;
	animName = name;
	shouldLoop = loop;
	animRate = loopSpd;
	duration = dur;
	player = id;
	ped = pedid;
	print("Set 'player' variable to: " .. player);
	print("Set 'ped' variable to: " .. ped);
	
	ClearPedTasksImmediately(ped); -- Clear any prior animations or actions

The original code I had there was:

RegisterNetEvent("BRPC:PlayAnim")
AddEventHandler("BRPC:PlayAnim", function(source, dict, name, prop, propX, propY, propZ, propRotX, propRotY, propRotZ, loop, dur, dropOnEnd)
	print("Received call for BRPC:PlayAnim event!");
	isAnimating = false; -- Reset isAnimating to false
	
	-- Get/Set the variables
	animDict = dict;
	animName = name;
	shouldLoop = loop;
	animRate = loopSpd;
	duration = dur;
	player = source;
	ped = GetPlayerPed(source);
	print("Set 'player' variable to: " .. player);
	print("Set 'ped' variable to: " .. ped);
	
	ClearPedTasksImmediately(ped); -- Clear any prior animations or actions

Because I need every client to be told what ped is animating, otherwise it’d only animate on the screen of the client I sent it to. No?
If (in the client script) I used “GetPlayerPed(-1)” that would get the current user’s ped, so either it’d execute for all players, even those that didn’t use the command (as it did before). Or I only send the “BRPC:PlayAnim” request to the client supposed to play the animation, but would that the sync over the network? I feel like if I was to do that, nobody else would see the animation… Unless I’m mistaken that is (which is entirely possible since I’m here with something that isn’t working :joy: )

I dont have a friend to test right not… but i think if you play a animation with the esx methods, just playing the anim at one, all the others players will see it.

edit to clarify: you only need send the “ BRPC:PlayAnim ” request to the client supposed to play the animation

Using “ GetPlayerPed(-1) you will get the ped of the current user, not all, to do that you have to send this event to all players who needed it from server script.

A good example is this part of esx script:

function startScenario(anim)
	TaskStartScenarioInPlace(PlayerPedId(), anim, 0, false)
end

Here play the animation without try sync a serverside event and it is known this resource works properly and others can see the animation.

Alright, I didn’t realize that “TaskPlayAnim” would tell other clients that they were animating.
Thanks!
I think I’ve fixed it, I’ve just messaged our testers to get one on to confirm that it doesn’t only work with me on.

EDIT: If it does work I’ll be sure to post what I did just in-case anybody else is interested.

Alright then! Solved!

Note: It seems that contrary to what I imagined the TaskPlayAnim function will inform other players of who is using it! So even if it is called clientside it doesn’t need “syncronizing” which is essentially what I was trying to implement.

Thanks for your help Knatus53! :wink:

Perfect! Glad to can help ^^