Browse Source

Moved chat lobby interaction to generic EOSVoiceChat class

master
Nico de Poel 5 years ago
parent
commit
7056ef18ce
  1. 187
      Assets/Scripts/EOSVoiceChat.cs
  2. 11
      Assets/Scripts/EOSVoiceChat.cs.meta
  3. 91
      Assets/Scripts/MagnificentVoiceChat.cs

187
Assets/Scripts/EOSVoiceChat.cs

@ -0,0 +1,187 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Epic.OnlineServices;
using Epic.OnlineServices.Lobby;
using Epic.OnlineServices.RTC;
using Epic.OnlineServices.RTCAudio;
using UnityEngine;
/// <summary>
/// Generic re-usable cross-platform class to provide common voice chat functionality based on the EOS Voice Chat service.
/// This class does not know anything about EOS platform initialization or authentication; it just takes the required
/// EOS interfaces and exposes a number of game-related voice functions.
/// </summary>
public class EOSVoiceChat
{
private const uint DefaultMaxChatPlayers = 16; // "Lobbies that generate conference rooms must have <= 16 max players"
private readonly LobbyInterface lobbyInterface;
private readonly RTCInterface rtcInterface;
private readonly RTCAudioInterface audioInterface;
private readonly Func<ProductUserId> productUserProvider;
private string connectedLobbyId;
public bool IsConnected => lobbyInterface != null && rtcInterface != null && audioInterface != null && !string.IsNullOrEmpty(connectedLobbyId);
/// <summary>
/// Provide the required interfaces for voice chat. Product User ID is provided through a callback, so that the
/// same instance of this class can remain in use even if the logged in user changes.
/// </summary>
public EOSVoiceChat(
LobbyInterface lobbyInterface, RTCInterface rtcInterface, RTCAudioInterface audioInterface,
Func<ProductUserId> productUserProvider)
{
this.lobbyInterface = lobbyInterface;
this.rtcInterface = rtcInterface;
this.audioInterface = audioInterface;
this.productUserProvider = productUserProvider;
}
/// <summary>
/// Join an existing chat lobby or create a new one.
/// The completion callback is invoked on both success and failure, and can be used to set up the chat lobby's initial parameters.
/// </summary>
public void ConnectToChat(string chatLobbyName, Action<bool> onCompleted = null, uint maxChatPlayers = DefaultMaxChatPlayers)
{
DisconnectChat(); // Leave any currently connected chat lobby
lobbyInterface.CreateLobbySearch(new CreateLobbySearchOptions { MaxResults = 1 }, out var searchHandle);
searchHandle.SetLobbyId(new LobbySearchSetLobbyIdOptions { LobbyId = chatLobbyName });
var localUserId = productUserProvider.Invoke();
searchHandle.Find(new LobbySearchFindOptions { LocalUserId = localUserId }, null, findData =>
{
switch (findData.ResultCode)
{
case Result.Success:
searchHandle.CopySearchResultByIndex(new LobbySearchCopySearchResultByIndexOptions { LobbyIndex = 0 }, out var lobbyDetails);
Debug.Log("Found existing lobby, joining...");
lobbyInterface.JoinLobby
(
new JoinLobbyOptions
{
LocalUserId = localUserId,
LobbyDetailsHandle = lobbyDetails,
PresenceEnabled = false,
},
null,
data => HandleLobbyJoined(data, onCompleted)
);
break;
default:
Debug.Log($"Creating new chat lobby...");
lobbyInterface.CreateLobby
(
new CreateLobbyOptions
{
LocalUserId = localUserId,
AllowInvites = false,
PermissionLevel = LobbyPermissionLevel.Publicadvertised,
PresenceEnabled = false,
MaxLobbyMembers = maxChatPlayers,
DisableHostMigration = false,
LobbyId = chatLobbyName,
BucketId = Application.productName, // TODO: do we need anything more specific than this?
EnableRTCRoom = true,
},
chatLobbyName,
data => HandleLobbyCreated(data, onCompleted)
);
break;
}
});
}
private void HandleLobbyCreated(CreateLobbyCallbackInfo data, Action<bool> onCompleted)
{
switch (data.ResultCode)
{
case Result.Success:
connectedLobbyId = data.LobbyId;
Debug.Log($"Chat lobby creation successful, lobby ID = {connectedLobbyId}");
onCompleted?.Invoke(true);
break;
case Result.LobbyLobbyAlreadyExists:
// This can happen if two clients try to create the same lobby at the same time, a classic race condition.
// Try to join the other client's newly created chat lobby instead.
connectedLobbyId = null;
Debug.Log("Chat lobby already exists, attempting to join it...");
ConnectToChat((string)data.ClientData, onCompleted);
break;
default:
connectedLobbyId = null;
Debug.LogError($"Chat lobby creation failed, result code = {data.ResultCode}");
onCompleted?.Invoke(false);
break;
}
}
private void HandleLobbyJoined(JoinLobbyCallbackInfo data, Action<bool> onCompleted)
{
switch (data.ResultCode)
{
case Result.Success:
connectedLobbyId = data.LobbyId;
Debug.Log($"Chat lobby joined successfully, lobby ID = {connectedLobbyId}");
onCompleted?.Invoke(true);
break;
default:
connectedLobbyId = null;
Debug.LogError($"Chat lobby join failed, result code = {data.ResultCode}");
onCompleted?.Invoke(false);
break;
}
}
public void DisconnectChat()
{
if (!IsConnected)
return;
lobbyInterface.LeaveLobby
(
new LeaveLobbyOptions
{
LocalUserId = productUserProvider.Invoke(),
LobbyId = connectedLobbyId,
},
null,
data => { }
);
connectedLobbyId = null;
}
/// <summary>
/// Mute or unmute the local player's voice chat. This can be used to implement push-to-talk.
/// </summary>
public void SetLocalMuted(bool muted)
{
if (!IsConnected)
return;
}
/// <summary>
/// Mute or unmute a specific remove player. This can be used to filter out specific players in the chat lobby,
/// or for manually muting toxic players.
/// </summary>
public void SetRemoteMuted(string playerId, bool muted)
{
if (!IsConnected)
return;
}
/// <summary>
/// Set all remote players to muted. This can be used during loading screens, or to initialize the chat lobby
/// when chatting with only a small subset of players.
/// </summary>
public void MuteAllRemote()
{
if (!IsConnected)
return;
}
}

11
Assets/Scripts/EOSVoiceChat.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f668ddd1628206e4b83baeb572784acd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

91
Assets/Scripts/MagnificentVoiceChat.cs

@ -33,7 +33,7 @@ public class MagnificentVoiceChat : MonoBehaviour
private EpicAccountId localEpicAccountId;
private ProductUserId localProductUserId;
private string lobbyId;
private EOSVoiceChat voiceChat;
private string XAudio29DllPath =>
#if UNITY_EDITOR
@ -125,6 +125,8 @@ public class MagnificentVoiceChat : MonoBehaviour
Credentials = GetEpicCredentials(),
ScopeFlags = AuthScopeFlags.BasicProfile,
}, null, HandleLoginResult);
voiceChat = new EOSVoiceChat(lobbyInterface, rtcInterface, audioInterface, () => localProductUserId);
}
private Credentials GetEpicCredentials() // This is platform-specific
@ -213,80 +215,16 @@ public class MagnificentVoiceChat : MonoBehaviour
private void CreateOrJoinVoiceLobby()
{
lobbyInterface.CreateLobbySearch(new CreateLobbySearchOptions { MaxResults = 1 }, out var searchHandle);
searchHandle.SetLobbyId(new LobbySearchSetLobbyIdOptions { LobbyId = DebugLobbyId });
searchHandle.Find(new LobbySearchFindOptions { LocalUserId = localProductUserId }, null, findData =>
voiceChat.ConnectToChat(DebugLobbyId, success =>
{
switch (findData.ResultCode)
{
case Result.Success:
searchHandle.CopySearchResultByIndex(new LobbySearchCopySearchResultByIndexOptions { LobbyIndex = 0 }, out var lobbyDetails);
Debug.Log("Found existing lobby, joining...");
status.AppendLine("Found existing lobby, joining...");
lobbyInterface.JoinLobby(new JoinLobbyOptions
{
LocalUserId = localProductUserId,
LobbyDetailsHandle = lobbyDetails,
PresenceEnabled = false,
}, null, HandleLobbyJoined);
break;
default:
Debug.Log("Creating new lobby...");
status.AppendLine("Creating new lobby...");
// Lobby creation options should probably be platform-specific; generated lobby ID and max members depends on the chat scheme
lobbyInterface.CreateLobby(new CreateLobbyOptions
{
LocalUserId = localProductUserId,
AllowInvites = false,
PermissionLevel = LobbyPermissionLevel.Publicadvertised,
PresenceEnabled = false,
MaxLobbyMembers = 16, // "Lobbies that generate conference rooms must have <= 16 max players"
DisableHostMigration = false,
LobbyId = DebugLobbyId,
BucketId = DebugBucketId, // Something that combines front, game mode, region, etc (or maybe just the room ID)
EnableRTCRoom = true,
}, null, HandleLobbyCreated);
break;
}
Debug.Log($"Chat lobby connect result = {success}");
if (success)
status.AppendLine("Chat lobby successfully connected!");
else
status.AppendLine("Chat lobby connect failure...");
});
}
private void HandleLobbyCreated(CreateLobbyCallbackInfo data)
{
switch (data.ResultCode)
{
case Result.Success:
lobbyId = data.LobbyId;
Debug.Log("Lobby creation successful: " + lobbyId);
status.AppendLine("Lobby creation successful: " + lobbyId);
break;
default:
Debug.Log("Lobby creation failed, result code = " + data.ResultCode);
status.AppendLine("Lobby creation failed");
break;
}
}
private void HandleLobbyJoined(JoinLobbyCallbackInfo data)
{
switch (data.ResultCode)
{
case Result.Success:
lobbyId = data.LobbyId;
Debug.Log("Lobby joined successfully: " + lobbyId);
status.AppendLine("Lobby joined successfully: " + lobbyId);
break;
default:
Debug.Log("Lobby join failed, result code = " + data.ResultCode);
status.AppendLine("Lobby join failed");
break;
}
}
void Update()
{
platformInterface.Tick();
@ -294,15 +232,10 @@ public class MagnificentVoiceChat : MonoBehaviour
private void OnDestroy()
{
if (lobbyInterface != null && lobbyId != null)
if (voiceChat != null)
{
lobbyInterface.LeaveLobby(new LeaveLobbyOptions
{
LocalUserId = localProductUserId,
LobbyId = lobbyId,
}, null, data => { });
lobbyId = null;
voiceChat.DisconnectChat();
voiceChat = null;
}
if (platformInterface != null)

Loading…
Cancel
Save