You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
15 KiB
430 lines
15 KiB
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using Epic.OnlineServices;
|
|
using Epic.OnlineServices.Auth;
|
|
using Epic.OnlineServices.Connect;
|
|
using Epic.OnlineServices.Lobby;
|
|
using Epic.OnlineServices.Logging;
|
|
using Epic.OnlineServices.Platform;
|
|
using Epic.OnlineServices.RTC;
|
|
using Epic.OnlineServices.RTCAudio;
|
|
using UnityEngine;
|
|
using Credentials = Epic.OnlineServices.Auth.Credentials;
|
|
using LoginCallbackInfo = Epic.OnlineServices.Auth.LoginCallbackInfo;
|
|
using LoginOptions = Epic.OnlineServices.Auth.LoginOptions;
|
|
|
|
#if UNITY_GAMECORE
|
|
using Unity.GameCore;
|
|
using UnityEngine.GameCore;
|
|
#endif
|
|
|
|
public class MagnificentVoiceChat : MonoBehaviour
|
|
{
|
|
private const string DebugLobbyId = "a0f6a51f-6b61-4c95-9ed8-a1d508fe4eb6";
|
|
private const string DebugBucketId = "foobar";
|
|
|
|
private readonly StringBuilder status = new StringBuilder("Status:\n");
|
|
|
|
private PlatformInterface platformInterface;
|
|
private AuthInterface authInterface;
|
|
private ConnectInterface connectInterface;
|
|
private LobbyInterface lobbyInterface;
|
|
private RTCInterface rtcInterface;
|
|
private RTCAudioInterface audioInterface;
|
|
|
|
private EpicAccountId localEpicAccountId;
|
|
private ProductUserId localProductUserId;
|
|
|
|
private EOSVoiceChat voiceChat;
|
|
|
|
private string xstsToken;
|
|
|
|
private string XAudio29DllPath =>
|
|
#if UNITY_EDITOR
|
|
Path.Combine(Application.dataPath, @"Plugins\EpicOnlineServices\Bin\x64\xaudio2_9redist.dll");
|
|
#else
|
|
Path.Combine(Application.dataPath, @"Plugins\x86_64\xaudio2_9redist.dll");
|
|
#endif
|
|
|
|
IEnumerator Start()
|
|
{
|
|
#if UNITY_EDITOR && UNITY_STANDALONE
|
|
LoadLibrary();
|
|
#elif UNITY_GAMECORE
|
|
int hresult = SDK.XGameRuntimeInitialize();
|
|
if (HR.FAILED(hresult))
|
|
{
|
|
Debug.LogError($"Error initializing game runtime, hresult = 0x{hresult:X}");
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log("GXDK game runtime initialized.");
|
|
|
|
hresult = SDK.XBL.XblInitialize(GameCoreSettings.SCID);
|
|
if (HR.FAILED(hresult))
|
|
{
|
|
Debug.LogError($"Error initializing Xbox Live services, hresult = 0x{hresult:X}");
|
|
yield break;
|
|
}
|
|
|
|
hresult = SDK.XGameGetXboxTitleId(out uint titleId);
|
|
if (HR.FAILED(hresult))
|
|
{
|
|
Debug.LogError($"Error obtaining Xbox Title ID, hresult = 0x{hresult:X}");
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log("Xbox Live services initialized.");
|
|
|
|
yield return new WaitForSeconds(5f);
|
|
#endif
|
|
|
|
var result = PlatformInterface.Initialize(new InitializeOptions
|
|
{
|
|
ProductName = "WW1Test",
|
|
ProductVersion = "1.0.0.0",
|
|
#if UNITY_GAMECORE
|
|
AllocateMemoryFunction = Marshal.GetFunctionPointerForDelegate((SystemLibrary.AllocateMemoryFunc)SystemLibrary.AllocateMemory),
|
|
ReallocateMemoryFunction = Marshal.GetFunctionPointerForDelegate((SystemLibrary.ReallocateMemoryFunc)SystemLibrary.ReallocateMemory),
|
|
ReleaseMemoryFunction = Marshal.GetFunctionPointerForDelegate((SystemLibrary.ReleaseMemoryFunc)SystemLibrary.ReleaseMemory),
|
|
#endif
|
|
});
|
|
|
|
if (result != Result.Success)
|
|
{
|
|
Debug.LogError("Failed to initialize EOS, result = " + result);
|
|
status.AppendLine("EOS initialization failed...");
|
|
yield break;
|
|
}
|
|
|
|
LoggingInterface.SetLogLevel(LogCategory.AllCategories, LogLevel.Warning);
|
|
LoggingInterface.SetCallback(OnEOSLogMessage);
|
|
|
|
#if UNITY_STANDALONE_WIN
|
|
Debug.Log("XAudio library path: " + XAudio29DllPath);
|
|
|
|
var options = new WindowsOptions // Okay so this will need to be platform-specific
|
|
{
|
|
ProductId = "b21a28c2c5404c8099d72f5a28c59c16",
|
|
SandboxId = "b630f2c3933a4838a971ce53d5b0db3b",
|
|
DeploymentId = "9a36f589572c492fbee14bd299173c12",
|
|
|
|
ClientCredentials = new ClientCredentials
|
|
{
|
|
ClientId = "xyza7891UOFoUhfvfbKgO2xRCIiuAIjH",
|
|
ClientSecret = "NArwIQT1laFfsS7fdcN1MKDdgwy490w9MBJsAlHN4QI",
|
|
},
|
|
|
|
Flags = PlatformFlags.DisableOverlay,
|
|
|
|
CacheDirectory = null,
|
|
EncryptionKey = null,
|
|
|
|
IsServer = false,
|
|
|
|
RTCOptions = new WindowsRTCOptions // This is also platform-specific
|
|
{
|
|
PlatformSpecificOptions = new WindowsRTCOptionsPlatformSpecificOptions
|
|
{
|
|
XAudio29DllPath = XAudio29DllPath
|
|
}
|
|
},
|
|
};
|
|
#else
|
|
var options = new Options
|
|
{
|
|
ProductId = "b21a28c2c5404c8099d72f5a28c59c16",
|
|
SandboxId = "b630f2c3933a4838a971ce53d5b0db3b",
|
|
DeploymentId = "9a36f589572c492fbee14bd299173c12",
|
|
|
|
ClientCredentials = new ClientCredentials
|
|
{
|
|
ClientId = "xyza7891UOFoUhfvfbKgO2xRCIiuAIjH",
|
|
ClientSecret = "NArwIQT1laFfsS7fdcN1MKDdgwy490w9MBJsAlHN4QI",
|
|
},
|
|
|
|
Flags = PlatformFlags.DisableOverlay,
|
|
|
|
CacheDirectory = null,
|
|
EncryptionKey = null,
|
|
|
|
IsServer = false,
|
|
|
|
RTCOptions = new RTCOptions(),
|
|
};
|
|
#endif
|
|
|
|
platformInterface = PlatformInterface.Create(options);
|
|
|
|
if (platformInterface == null)
|
|
{
|
|
Debug.LogError("Failed to create EOS platform interface");
|
|
status.AppendLine("Failed to create EOS platform interface");
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log("EOS platform interface successfully created!");
|
|
status.AppendLine("EOS platform interface created");
|
|
|
|
authInterface = platformInterface.GetAuthInterface();
|
|
status.AppendLine("Auth interface: " + authInterface);
|
|
|
|
connectInterface = platformInterface.GetConnectInterface();
|
|
status.AppendLine("Connect interface: " + connectInterface);
|
|
|
|
lobbyInterface = platformInterface.GetLobbyInterface();
|
|
status.AppendLine("Lobby interface: " + lobbyInterface);
|
|
|
|
rtcInterface = platformInterface.GetRTCInterface(); // Real-time communication, needed for audio
|
|
status.AppendLine("RTC interface: " + rtcInterface);
|
|
|
|
audioInterface = rtcInterface.GetAudioInterface();
|
|
status.AppendLine("Audio interface: " + audioInterface);
|
|
|
|
voiceChat = new EOSVoiceChat(lobbyInterface, rtcInterface, audioInterface, () => localProductUserId);
|
|
voiceChat.OnChatConnected += () => status.AppendLine("Chat lobby successfully connected!");
|
|
voiceChat.OnChatConnectionFailed += () => status.AppendLine("Chat lobby connection failed...");
|
|
voiceChat.OnChatDisconnected += () => status.AppendLine("Chat lobby disconnected");
|
|
voiceChat.OnChatUserJoined += userId => status.AppendLine($"Chat user {userId} joined");
|
|
voiceChat.OnChatUserLeft += userId => status.AppendLine($"Chat user {userId} left");
|
|
|
|
#if UNITY_GAMECORE
|
|
SDK.XUserAddAsync(XUserAddOptions.AddDefaultUserAllowingUI, (hr, userHandle) =>
|
|
{
|
|
if (HR.FAILED(hr))
|
|
{
|
|
Debug.LogError($"Add Xbox user failed, hresult = 0x{hr:X}");
|
|
status.AppendLine("Add Xbox user failed...");
|
|
return;
|
|
}
|
|
|
|
status.AppendLine("Xbox user added");
|
|
SDK.XUserGetTokenAndSignatureUtf16Async(userHandle, XUserGetTokenAndSignatureOptions.ForceRefresh,
|
|
"GET", "https://api.epicgames.dev/", null, null, HandleTokenAndSignature);
|
|
});
|
|
|
|
yield return new WaitUntil(() => !string.IsNullOrEmpty(xstsToken));
|
|
#endif
|
|
|
|
authInterface.Login(new LoginOptions
|
|
{
|
|
Credentials = GetEpicCredentials(),
|
|
ScopeFlags = AuthScopeFlags.BasicProfile,
|
|
}, null, HandleLoginResult);
|
|
}
|
|
|
|
#if UNITY_GAMECORE
|
|
private void HandleTokenAndSignature(int hresult, XUserGetTokenAndSignatureUtf16Data tokenAndSignature)
|
|
{
|
|
if (HR.FAILED(hresult))
|
|
{
|
|
Debug.LogError($"Xbox Live authentication failed, hresult = 0x{hresult:X}");
|
|
status.AppendLine("Xbox Live authentication failed...");
|
|
return;
|
|
}
|
|
|
|
Debug.Log($"Xbox Live authenticated, XSTS token = {tokenAndSignature.Token}");
|
|
status.AppendLine("Xbox Live successfully authenticated");
|
|
xstsToken = tokenAndSignature.Token;
|
|
}
|
|
#endif
|
|
|
|
private Credentials GetEpicCredentials() // This is platform-specific
|
|
{
|
|
#if UNITY_STANDALONE
|
|
return new Credentials
|
|
{
|
|
// Type = LoginCredentialType.AccountPortal, // Use ExternalAuth on console platform
|
|
Id = "192.168.1.100:8888",
|
|
Type = LoginCredentialType.Developer,
|
|
Token = SystemInfo.deviceName,
|
|
};
|
|
#elif UNITY_GAMECORE
|
|
return new Credentials
|
|
{
|
|
Type = LoginCredentialType.ExternalAuth,
|
|
ExternalType = ExternalCredentialType.XblXstsToken,
|
|
Token = xstsToken,
|
|
};
|
|
#elif UNITY_PS4 || UNITY_PS5
|
|
#endif
|
|
}
|
|
|
|
private void HandleLoginResult(LoginCallbackInfo data)
|
|
{
|
|
switch (data.ResultCode)
|
|
{
|
|
case Result.Success:
|
|
localEpicAccountId = data.LocalUserId;
|
|
Debug.Log("EOS login successful: " + localEpicAccountId);
|
|
status.AppendLine("EOS login successful: " + localEpicAccountId);
|
|
|
|
authInterface.CopyUserAuthToken(new CopyUserAuthTokenOptions(), localEpicAccountId, out Token token);
|
|
Debug.Log($"User auth access token: {token.AccessToken}");
|
|
|
|
connectInterface.Login(new Epic.OnlineServices.Connect.LoginOptions
|
|
{
|
|
#if UNITY_STANDALONE
|
|
Credentials = new Epic.OnlineServices.Connect.Credentials
|
|
{
|
|
Type = ExternalCredentialType.Epic, // Can be XSTS or PSN ID as well, platform-specific
|
|
Token = token.AccessToken,
|
|
},
|
|
#elif UNITY_GAMECORE
|
|
Credentials = new Epic.OnlineServices.Connect.Credentials
|
|
{
|
|
Type = ExternalCredentialType.XblXstsToken, // Isn't this kinda redundant? Should we be logging in to our Epic account here?
|
|
Token = xstsToken,
|
|
},
|
|
#elif UNITY_PS4 || UNITY_PS5
|
|
#endif
|
|
}, null, HandleConnectResult);
|
|
break;
|
|
default:
|
|
Debug.Log("EOS login failed, result code = " + data.ResultCode);
|
|
status.AppendLine("EOS login failed");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void HandleConnectResult(Epic.OnlineServices.Connect.LoginCallbackInfo data)
|
|
{
|
|
switch (data.ResultCode)
|
|
{
|
|
case Result.Success:
|
|
localProductUserId = data.LocalUserId;
|
|
Debug.Log("Connect successful: " + localProductUserId);
|
|
status.AppendLine("Connect successful: " + localProductUserId);
|
|
|
|
CreateOrJoinVoiceLobby();
|
|
break;
|
|
case Result.InvalidUser:
|
|
Debug.Log("Invalid user, creating user...");
|
|
status.AppendLine("Invalid user, creating user...");
|
|
|
|
connectInterface.CreateUser(new CreateUserOptions
|
|
{
|
|
ContinuanceToken = data.ContinuanceToken,
|
|
}, null, HandleUserCreated);
|
|
|
|
break;
|
|
default:
|
|
Debug.Log("Connect failed, result code = " + data.ResultCode);
|
|
status.AppendLine("Connect failed");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void HandleUserCreated(CreateUserCallbackInfo data)
|
|
{
|
|
switch (data.ResultCode)
|
|
{
|
|
case Result.Success:
|
|
localProductUserId = data.LocalUserId;
|
|
Debug.Log("User creation successful: " + localProductUserId);
|
|
status.AppendLine("User creation successful: " + localProductUserId);
|
|
|
|
CreateOrJoinVoiceLobby();
|
|
break;
|
|
default:
|
|
Debug.Log("User creation failed, result code = " + data.ResultCode);
|
|
status.AppendLine("User creation failed");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void CreateOrJoinVoiceLobby()
|
|
{
|
|
voiceChat.ConnectToChat(DebugLobbyId);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (platformInterface != null)
|
|
platformInterface.Tick();
|
|
|
|
#if UNITY_GAMECORE
|
|
SDK.XTaskQueueDispatch();
|
|
#endif
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (voiceChat != null)
|
|
{
|
|
voiceChat.Dispose();
|
|
voiceChat = null;
|
|
}
|
|
|
|
if (platformInterface != null)
|
|
{
|
|
platformInterface.Release();
|
|
platformInterface = null;
|
|
}
|
|
|
|
PlatformInterface.Shutdown();
|
|
|
|
#if UNITY_EDITOR && UNITY_STANDALONE
|
|
UnloadLibrary();
|
|
#endif
|
|
}
|
|
|
|
#if UNITY_EDITOR && UNITY_STANDALONE
|
|
private IntPtr eosLbraryHandle;
|
|
|
|
private void LoadLibrary()
|
|
{
|
|
eosLbraryHandle = SystemLibrary.LoadLibrary($@"Assets\Plugins\EpicOnlineServices\Bin\{Config.LibraryName}.dll");
|
|
if (eosLbraryHandle == IntPtr.Zero)
|
|
{
|
|
throw new Exception("Could not load EOS library!");
|
|
}
|
|
|
|
Bindings.Hook(eosLbraryHandle, SystemLibrary.GetProcAddress);
|
|
|
|
Debug.Log("Hooked EOS library bindings");
|
|
status.AppendLine("Hooked EOS library bindings");
|
|
}
|
|
|
|
private void UnloadLibrary()
|
|
{
|
|
Debug.Log("Unhooking EOS library bindings");
|
|
|
|
Bindings.Unhook();
|
|
|
|
if (eosLbraryHandle != IntPtr.Zero)
|
|
{
|
|
SystemLibrary.FreeLibrary(eosLbraryHandle);
|
|
eosLbraryHandle = IntPtr.Zero;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
private void OnEOSLogMessage(LogMessage message)
|
|
{
|
|
switch (message.Level)
|
|
{
|
|
case LogLevel.Fatal:
|
|
case LogLevel.Error:
|
|
Debug.LogError(message.Message);
|
|
break;
|
|
case LogLevel.Warning:
|
|
Debug.LogWarning(message.Message);
|
|
break;
|
|
default:
|
|
Debug.Log(message.Message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
GUI.matrix = Matrix4x4.Scale(new Vector3(2, 2, 1));
|
|
|
|
GUILayout.Label(status.ToString());
|
|
}
|
|
}
|