Unity

유니티 스팀 멀티 연동하기 - 5. 게임 내 초대 구현

devkimluxx 2023. 10. 13. 22:01
728x90

스팀에서 실행한 게임은, 게임 도중 Shift + Tab 키를 누르면 스팀 오버레이가 펼쳐지며 친구를 초대할 수 있다.

하지만, 스팀을 오래하지 않거나, 멀티가 익숙하지 않은 사람은 이런 초대 방법을 모를 수 있다.

그렇기 때문에 대부분의 게임에서는 스팀 오버레이 없이 게임 내에서 초대하는 기능을 따로 또 넣고는 한다.

 

이 기능은 스팀 구현은 정보가 거의 없어서 API 도큐먼트를 직접 읽으면서 찾을 수밖에 없었다.

아래는 스팀 친구 초대 UI 패널을 띄울 때 친구 목록을 가져오고 생성하는 부분을 잘라온 것이다.

    private void UpdateFriendList()
    {
        var c = content.GetComponentsInChildren<Transform>();
        c.ToList().ForEach(x =>
        {
            if(x != content)
                Destroy(x.gameObject);
        });

        List<Steamworks.CSteamID> friendsList = new List<Steamworks.CSteamID>();
        
        int friendCount = Steamworks.SteamFriends.GetFriendCount(Steamworks.EFriendFlags.k_EFriendFlagImmediate);
        for(int i = 0; i < friendCount; i++)
        {
            var friend = Steamworks.SteamFriends.GetFriendByIndex(i, Steamworks.EFriendFlags.k_EFriendFlagImmediate);

            if(Steamworks.SteamFriends.GetFriendPersonaState((Steamworks.CSteamID)friend.m_SteamID) != Steamworks.EPersonaState.k_EPersonaStateOffline)
            {
                GameObject obj = Instantiate(prefabPanelInviteItem, content, false);
                var controller = obj.GetComponent<PanelInviteItemController>();
                controller.PlayerSteamID = friend.m_SteamID;
                controller.PlayerName = Steamworks.SteamFriends.GetFriendPersonaName((Steamworks.CSteamID)friend.m_SteamID);
                controller.PlayerNameText.text = controller.PlayerName;

                friendsList.Add(friend);
            }

            
        }
        Debug.Log($"Steam friend Count : {friendsList.Count}");


    }

 

Steamworks.SteamFriends.GetFriendCount를 통해 가져올 친구의 숫자를 받아올 수 있다.

물론 패러미터로 가져올 친구의 조건을 필터링할 수 있다.

위에 나온대로 EFriendFlags를 입맛에 맞게 변경해주면 된다.

본인의 스팀 이름이 아닌, 친구의 이름을 가져오는 방법도 찾기가 좀 어려웠는데, Steamworks.SteamFriends.GetFriendPersonaName()을 사용해서 가져올 수 있고, 해당 친구의 스팀ID 값을 패러미터로 넣어주면 된다.

 

구현시 친구의 설정해놓은 아바타 사진을 가져와서 보여주고 싶다면, 아래의 리스트 아이템에 넣은 스크립트 예시를 고쳐 사용하면 된다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Steamworks;
using System;

public class PanelInviteItemController : MonoBehaviour
{
    public string PlayerName;
    public int ConnectionID;
    public ulong PlayerSteamID;
    private bool AvatarReceived;

    public Text PlayerNameText;
    public RawImage PlayerIcon;

    [SerializeField]
    private Button buttonInvite;

    protected Callback<AvatarImageLoaded_t> ImageLoaded;

    private void Start()
    {
        ImageLoaded = Callback<AvatarImageLoaded_t>.Create(OnImageLoaded);
        buttonInvite.onClick.AddListener(() =>
       {
           //SteamFriends.InviteUserToGame((CSteamID)PlayerSteamID, SteamLobby.Instance.CurrentLobbyID.ToString());
           SteamMatchmaking.InviteUserToLobby((CSteamID)SteamLobby.Instance.CurrentLobbyID, (CSteamID)PlayerSteamID);
       });
        SetPlayerValues();
    }

    private void OnImageLoaded(AvatarImageLoaded_t callback)
    {
        Debug.Log($"PlayerSteamID : {PlayerSteamID}");
        if(callback.m_steamID.m_SteamID == PlayerSteamID)
        {
            PlayerIcon.texture = GetSteamImageAsTexture2D(callback.m_iImage);
        }
        else//another player
            return;
    }

    void GetPlayerIcon()
    {
        
        int ImageID = SteamFriends.GetLargeFriendAvatar((CSteamID)PlayerSteamID);//SteamFriends.GetSmallFriendAvatar((CSteamID)PlayerSteamID); //
        if (ImageID == -1)
        {
            Debug.Log($"no profile image : {(CSteamID)PlayerSteamID}");
            return;
        }
            
        PlayerIcon.texture = GetSteamImageAsTexture2D(ImageID);
    }

    public void SetPlayerValues()
    {
        PlayerNameText.text = PlayerName;
        if (!AvatarReceived)
            GetPlayerIcon();
    }

    private Texture2D GetSteamImageAsTexture2D(int iImage)
    {
        Texture2D ret = null;
        uint ImageWidth;
        uint ImageHeight;
        bool bIsValid = SteamUtils.GetImageSize(iImage, out ImageWidth, out ImageHeight);

        if (bIsValid)
        {
            byte[] Image = new byte[ImageWidth * ImageHeight * 4];

            bIsValid = SteamUtils.GetImageRGBA(iImage, Image, (int)(ImageWidth * ImageHeight * 4));
            if (bIsValid)
            {
                ret = new Texture2D((int)ImageWidth, (int)ImageHeight, TextureFormat.RGBA32, false, true);
                ret.LoadRawTextureData(Image);
                ret.Apply();
            }
        }

        return ret;
    }

}

 

SteamFriends.GetLargeFriendAvatar()로 이미지ID값을 찾고, SteamUtils.GetImageRGBA()를 사용해서 가져올 수 있다.

byte[] 형식으로 가져오므로, 사이즈에 맞춰 RawTexture로 변환해 사용하면 된다.

테스트했을 때, 막상 구현해놨는데 이미지가 뒤집어져 나오면 이상한 게 아니고 정상이다.

데이터값 자체를 뒤집어주는 방법도 있겠지만, 복잡한 구현 없이 게임 내 Image를 rotation z값을 180도 돌리고, Scale x값을 -1로 변경해서 사용하면 편하다.

 

728x90