How do I get a steam avatar with OnlineSubsystemSteam

Hello everyone I currently have connected to the steam’s OnlineSubsystem and have managed to get both the players Steam ID as well as their Steam nickname. One final thing I’m looking at trying to get is the users profile picture. I’m wondering is it at all possible to do this out of the box with the OnlineSubsystem API or if I will actually have to include “ISteamFriends.h” and “ISteamUtils.h” and work with the raw Steamworks API?

Also if anyone has managed to get this working before, would they be willing to let me know how?

1 Like

Looks like you need to integrate it yourself using the Steam API. Wondering though why this isn’t part of the Online Subsystem? Is it planned and just not integrated yet? Is it something a developer could add and submit?

I ended up implementing it myself currently with the Steamworks API with this function here, based on what I read from that thread and what I managed to hack together to flip blue and red color channels. I do still find it very odd that there is no built in support for this with OnlineSubsystemSteam as far as I could tell, but I could be missing it. If I am and anyone knows I’d be grateful to be pointed in the right direction.

UTexture2D *ATheGamePlayerController::getSteamAvatar() {
	uint32 Width;
	uint32 Height;

	if (SteamAPI_Init())
	{
		//Getting the PictureID from the SteamAPI and getting the Size with the ID
		int Picture = SteamFriends()->GetMediumFriendAvatar(SteamUser()->GetSteamID());
		SteamUtils()->GetImageSize(Picture, &Width, &Height);


		if (Width > 0 && Height > 0)
		{
			//Creating the buffer "oAvatarRGBA" and then filling it with the RGBA Stream from the Steam Avatar
			BYTE *oAvatarRGBA = new BYTE[Width * Height * 4];


			//Filling the buffer with the RGBA Stream from the Steam Avatar and creating a UTextur2D to parse the RGBA Steam in
			SteamUtils()->GetImageRGBA(Picture, (uint8*)oAvatarRGBA, 4 * Height * Width * sizeof(char));

			//Swap R and B channels because for some reason the games whack
			for (uint32 i = 0; i < (Width * Height * 4); i += 4)
			{
				uint8 Temp = oAvatarRGBA[i + 0];
				oAvatarRGBA[i + 0] = oAvatarRGBA[i + 2];
				oAvatarRGBA[i + 2] = Temp;
			}

			UTexture2D* Avatar = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8);

			//MAGIC!
			uint8* MipData = (uint8*)Avatar->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
			FMemory::Memcpy(MipData, (void*)oAvatarRGBA, Height * Width * 4);
			Avatar->PlatformData->Mips[0].BulkData.Unlock();

			//Setting some Parameters for the Texture and finally returning it
			Avatar->PlatformData->NumSlices = 1;
			Avatar->NeverStream = true;
			//Avatar->CompressionSettings = TC_EditorIcon;

			Avatar->UpdateResource();

			return Avatar;
		}
		return nullptr;
	}
	return nullptr;
}
1 Like

Worked great for us. We did add a parameter passed in, FString UserSteamID, where we collect all the steam ID’s of joined players as hexadecimal strings. When each player joins they send a message to the server to add their steam ID hex string to the Player State on the server.

Then we can convert back and forth…

CSteamID USteamBridge::SteamIDStringToCSteamID(FString s)
{
	uint64 i64 = 0;
	int convCount = sscanf_s( TCHAR_TO_ANSI(*s), "%llu", &i64 );
	if (convCount == 0)
	{
		UE_LOG(DSS_STEAM, Log, TEXT("SteamIDStringToCSteamID - invalid input string %s"), *s);
		return CSteamID((uint64)0);
	}
	return CSteamID(i64);
}

FString USteamBridge::CSteamIDToString(CSteamID i)
{
	sprintf_s( steamidbuf, sizeof(steamidbuf), "%llu", i.ConvertToUint64() );
	return FString(steamidbuf);
}

Then we can get the avatar of any player.

(top of the function)

UTexture2D * USteamBridge::GetSteamAvatar(FString PlayerSteamID) {
	uint32 Width;
	uint32 Height;

	if (SteamAPI_IsSteamRunning())
	{
		CSteamID PlayerRawID = SteamIDStringToCSteamID(PlayerSteamID);
		//Getting the PictureID from the SteamAPI and getting the Size with the ID
		int Picture = SteamFriends()->GetMediumFriendAvatar(PlayerRawID);

For the record, swaping the color channels is completely unncessary if you replace

line 29:

UTexture2D* Avatar = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8);

with

UTexture2D* Avatar = UTexture2D::CreateTransient(Width, Height, PF_R8G8B8A8);

Be sure to read through the code you find online! But thanks, your sample really saved me a ton of time.

It’s worth noting that this example is also leaking HeightWidth4 memory every call, so you’ll want to deallocate your buffer, or better yet, use a TArray instead so it handles the allocations for you.