From 84e42243435ad2631249888e4e854f0d2b733122 Mon Sep 17 00:00:00 2001 From: mordentral Date: Thu, 17 Dec 2015 08:56:07 -0500 Subject: [PATCH] FirstCommitdf --- AdvancedSessions.uplugin | 21 + Resources/Icon128.png | Bin 0 -> 30266 bytes .../AdvancedSessions.Build.cs | 14 + .../Classes/AdvancedFriendsGameInstance.h | 109 +++++ .../Classes/AdvancedFriendsInterface.h | 44 ++ .../Classes/AdvancedFriendsLibrary.h | 56 +++ .../Classes/AdvancedSessionsLibrary.h | 143 +++++++ .../Classes/AdvancedVoiceLibrary.h | 96 +++++ .../Classes/CancelFindSessionsCallbackProxy.h | 44 ++ .../CreateSessionCallbackProxyAdvanced.h | 67 +++ .../Classes/EndSessionCallbackProxy.h | 44 ++ .../Classes/FindFriendSessionCallbackProxy.h | 50 +++ .../FindSessionsCallbackProxyAdvanced.h | 78 ++++ .../Classes/GetFriendsCallbackProxy.h | 48 +++ .../Classes/GetRecentPlayersCallbackProxy.h | 49 +++ .../Classes/SendFriendInviteCallbackProxy.h | 48 +++ .../UpdateSessionCallbackProxyAdvanced.h | 63 +++ .../Private/AdvancedFriendsGameInstance.cpp | 196 +++++++++ .../Private/AdvancedFriendsInterface.cpp | 9 + .../Private/AdvancedFriendsLibrary.cpp | 251 +++++++++++ .../Private/AdvancedSessions.cpp | 13 + .../Private/AdvancedSessions.h | 12 + .../Private/AdvancedSessionsLibrary.cpp | 397 ++++++++++++++++++ .../Private/AdvancedVoiceLibrary.cpp | 218 ++++++++++ .../Private/BlueprintDataDefinitions.h | 328 +++++++++++++++ .../CancelFindSessionsCallbackProxy.cpp | 71 ++++ .../CreateSessionCallbackProxyAdvanced.cpp | 135 ++++++ .../Private/EndSessionCallbackProxy.cpp | 79 ++++ .../FindFriendSessionCallbackProxy.cpp | 88 ++++ .../FindSessionsCallbackProxyAdvanced.cpp | 317 ++++++++++++++ .../Private/GetFriendsCallbackProxy.cpp | 81 ++++ .../Private/GetRecentPlayersCallbackProxy.cpp | 85 ++++ .../Private/OnlineSubSystemHeader.h | 14 + .../Private/SendFriendInviteCallbackProxy.cpp | 73 ++++ .../UpdateSessionCallbackProxyAdvanced.cpp | 120 ++++++ 35 files changed, 3461 insertions(+) create mode 100644 AdvancedSessions.uplugin create mode 100644 Resources/Icon128.png create mode 100644 Source/AdvancedSessions/AdvancedSessions.Build.cs create mode 100644 Source/AdvancedSessions/Classes/AdvancedFriendsGameInstance.h create mode 100644 Source/AdvancedSessions/Classes/AdvancedFriendsInterface.h create mode 100644 Source/AdvancedSessions/Classes/AdvancedFriendsLibrary.h create mode 100644 Source/AdvancedSessions/Classes/AdvancedSessionsLibrary.h create mode 100644 Source/AdvancedSessions/Classes/AdvancedVoiceLibrary.h create mode 100644 Source/AdvancedSessions/Classes/CancelFindSessionsCallbackProxy.h create mode 100644 Source/AdvancedSessions/Classes/CreateSessionCallbackProxyAdvanced.h create mode 100644 Source/AdvancedSessions/Classes/EndSessionCallbackProxy.h create mode 100644 Source/AdvancedSessions/Classes/FindFriendSessionCallbackProxy.h create mode 100644 Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h create mode 100644 Source/AdvancedSessions/Classes/GetFriendsCallbackProxy.h create mode 100644 Source/AdvancedSessions/Classes/GetRecentPlayersCallbackProxy.h create mode 100644 Source/AdvancedSessions/Classes/SendFriendInviteCallbackProxy.h create mode 100644 Source/AdvancedSessions/Classes/UpdateSessionCallbackProxyAdvanced.h create mode 100644 Source/AdvancedSessions/Private/AdvancedFriendsGameInstance.cpp create mode 100644 Source/AdvancedSessions/Private/AdvancedFriendsInterface.cpp create mode 100644 Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp create mode 100644 Source/AdvancedSessions/Private/AdvancedSessions.cpp create mode 100644 Source/AdvancedSessions/Private/AdvancedSessions.h create mode 100644 Source/AdvancedSessions/Private/AdvancedSessionsLibrary.cpp create mode 100644 Source/AdvancedSessions/Private/AdvancedVoiceLibrary.cpp create mode 100644 Source/AdvancedSessions/Private/BlueprintDataDefinitions.h create mode 100644 Source/AdvancedSessions/Private/CancelFindSessionsCallbackProxy.cpp create mode 100644 Source/AdvancedSessions/Private/CreateSessionCallbackProxyAdvanced.cpp create mode 100644 Source/AdvancedSessions/Private/EndSessionCallbackProxy.cpp create mode 100644 Source/AdvancedSessions/Private/FindFriendSessionCallbackProxy.cpp create mode 100644 Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp create mode 100644 Source/AdvancedSessions/Private/GetFriendsCallbackProxy.cpp create mode 100644 Source/AdvancedSessions/Private/GetRecentPlayersCallbackProxy.cpp create mode 100644 Source/AdvancedSessions/Private/OnlineSubSystemHeader.h create mode 100644 Source/AdvancedSessions/Private/SendFriendInviteCallbackProxy.cpp create mode 100644 Source/AdvancedSessions/Private/UpdateSessionCallbackProxyAdvanced.cpp diff --git a/AdvancedSessions.uplugin b/AdvancedSessions.uplugin new file mode 100644 index 0000000..f596ea8 --- /dev/null +++ b/AdvancedSessions.uplugin @@ -0,0 +1,21 @@ +{ + "FileVersion" : 3, + + "FriendlyName" : "Advanced Sessions", + "Version" : 1.9, + "VersionName": "1.9", + "EngineVersion" : 1579795, + "Description" : "Adds new blueprint functions to handle more advanced session operations.", + "Category" : "Advanced Sessions Plugin", + "CreatedBy" : "Joshua Statzer", + "CreatedByURL" : "N/A", + + "Modules" : + [ + { + "Name" : "AdvancedSessions", + "Type" : "RunTime", + "LoadingPhase" : "PreDefault" + } + ] +} \ No newline at end of file diff --git a/Resources/Icon128.png b/Resources/Icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2f1f18439ce025295996aa78335d8851efec6a GIT binary patch literal 30266 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

%jHsx}J=q%^f8rj|tVWM%RG+ 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 PersonInviting, const FOnlineSessionSearchResult& SessionToJoin); + + // After a session invite has been accepted by the local player this event is triggered, call JoinSession on the session result to join it + UFUNCTION(BlueprintImplementableEvent, Category = "AdvancedFriends") + void OnSessionInviteAccepted(int32 LocalPlayerNum, FBPUniqueNetId PersonInviting, const FBlueprintSessionResult& SessionToJoin); + + + // After a voice status has changed this event is triggered if the bEnableTalkingStatusDelegate property is true + UFUNCTION(BlueprintImplementableEvent, Category = "AdvancedVoice") + void OnPlayerTalkingStateChanged(FBPUniqueNetId PlayerId, bool bIsTalking); + + void OnPlayerTalkingStateChangedMaster(TSharedRef PlayerId, bool bIsTalking); + + FOnPlayerTalkingStateChangedDelegate PlayerTalkingStateChangedDelegate; + FDelegateHandle PlayerTalkingStateChangedDelegateHandle; + + //*** Session Invite Received From Friend ***// + // REMOVED BECAUSE IT NEVER GETS CALLED + /*FOnSessionInviteReceivedDelegate SessionInviteReceivedDelegate; + FDelegateHandle SessionInviteReceivedDelegateHandle; + + void OnSessionInviteReceivedMaster(const FUniqueNetId &InvitedPlayer, const FUniqueNetId &FriendInviting, const FOnlineSessionSearchResult& Session); + + // After a session invite has been sent from a friend this event is triggered, call JoinSession on the session result to join it + UFUNCTION(BlueprintImplementableEvent, Category = "AdvancedFriends") + void OnSessionInviteReceived(const FBPUniqueNetId &InvitedPlayer, const FBPUniqueNetId &FriendInviting, const FBlueprintSessionResult &Session); + */ + + //*** Friend Invite Accepted ***// + /*FOnInviteAcceptedDelegate FriendInviteAcceptedDelegate; + FDelegateHandle FriendInviteAcceptedDelegateHandle; + + void OnFriendInviteAcceptedDelegateMaster(const FUniqueNetId& LocalPlayer, const FUniqueNetId &PlayerInvited); + + // After a session invite has been accepted by a friend this event is triggered + UFUNCTION(BlueprintImplementableEvent, Category = "AdvancedFriends") + void OnFriendInviteAccepted(const FBPUniqueNetId &InvitedPlayer, const FBPUniqueNetId &PlayerInvited); + */ + + //*** Friend Invite Rejected ***// + /*FOnInviteRejectedDelegate SessionInviteRejectedByFriendDelegate; + FDelegateHandle InviteRejectedByFriendDelegateHandle; + + void OnFriendInviteRejectedDelegateMaster(const FUniqueNetId& LocalPlayer, const FUniqueNetId &PlayerDeclined); + + // After a friend invite has been rejected this event is triggered + UFUNCTION(BlueprintImplementableEvent, Category = "AdvancedFriends") + void OnFriendInviteRejected(const FBPUniqueNetId &InvitedPlayer, const FBPUniqueNetId &PlayerDeclined); + */ + + //*** Removed By Friend ***// + /*FOnFriendRemovedDelegate RemovedByFriendDelegate; + FDelegateHandle RemovedByFriendDelegateHandle; + + void OnRemovedByFriendDelegateMaster(const FUniqueNetId& LocalPlayer, const FUniqueNetId &FriendRemoved); + + // After a friend removed the player this event is triggered + UFUNCTION(BlueprintImplementableEvent, Category = "AdvancedFriends") + void OnRemovedByFriend(const FBPUniqueNetId &InvitedPlayer, const FBPUniqueNetId &FriendRemoved);*/ +}; + diff --git a/Source/AdvancedSessions/Classes/AdvancedFriendsInterface.h b/Source/AdvancedSessions/Classes/AdvancedFriendsInterface.h new file mode 100644 index 0000000..a985d38 --- /dev/null +++ b/Source/AdvancedSessions/Classes/AdvancedFriendsInterface.h @@ -0,0 +1,44 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "OnlineSubSystemHeader.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Online.h" +#include "OnlineSubsystem.h" +#include "OnlineFriendsInterface.h" +#include "OnlineUserInterface.h" +#include "OnlineMessageInterface.h" +#include "OnlinePresenceInterface.h" +#include "Engine/GameInstance.h" +#include "OnlineSessionInterface.h" +#include "OnlineSessionSettings.h" +#include "UObjectIterator.h" +#include "BlueprintDataDefinitions.h" +#include "AdvancedFriendsInterface.generated.h" + + +UINTERFACE(MinimalAPI) +class UAdvancedFriendsInterface : public UInterface +{ + GENERATED_UINTERFACE_BODY() +}; + +class IAdvancedFriendsInterface +{ + GENERATED_IINTERFACE_BODY() +public: + + // Called when the designated LocalUser has accepted a session invite, use JoinSession on result to connect + UFUNCTION(BlueprintImplementableEvent, meta = (DisplayName = "OnSessionInviteAccepted")) + void OnSessionInviteAccepted(FBPUniqueNetId PersonInviting, const FBlueprintSessionResult& SearchResult); + + // Called when the designated LocalUser has accepted a session invite, use JoinSession on result to connect + UFUNCTION(BlueprintImplementableEvent, meta = (DisplayName = "OnPlayerVoiceStateChanged")) + void OnPlayerVoiceStateChanged(FBPUniqueNetId PlayerId, bool bIsTalking); + + // REMOVED BECAUSE IT WAS NEVER BEING CALLED + // Called when the designated LocalUser has received a session invite, use JoinSession on result to connect + //UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "OnSessionInviteReceived")) + //void OnSessionInviteReceived(const FBPUniqueNetId &FriendInviting, const FBlueprintSessionResult &Session); + +}; diff --git a/Source/AdvancedSessions/Classes/AdvancedFriendsLibrary.h b/Source/AdvancedSessions/Classes/AdvancedFriendsLibrary.h new file mode 100644 index 0000000..f834b2e --- /dev/null +++ b/Source/AdvancedSessions/Classes/AdvancedFriendsLibrary.h @@ -0,0 +1,56 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "OnlineSubSystemHeader.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Online.h" +#include "OnlineSubsystem.h" +#include "OnlineFriendsInterface.h" +#include "OnlineUserInterface.h" +#include "OnlineMessageInterface.h" +#include "OnlinePresenceInterface.h" +#include "Engine/GameInstance.h" +#include "OnlineSessionInterface.h" + +#include "UObjectIterator.h" + +#include "AdvancedFriendsLibrary.generated.h" + + +//General Advanced Sessions Log +DECLARE_LOG_CATEGORY_EXTERN(AdvancedFriendsLog, Log, All); + + +UCLASS() +class UAdvancedFriendsLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + + //********* Friend List Functions *************// + + // Sends an Invite to the current online session to a list of friends + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedFriends|FriendsList", meta = (ExpandEnumAsExecs = "Result")) + static void SendSessionInviteToFriends(APlayerController *PlayerController, const TArray &Friends, TEnumAsByte &Result); + + // Sends an Invite to the current online session to a friend + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedFriends|FriendsList", meta = (ExpandEnumAsExecs = "Result")) + static void SendSessionInviteToFriend(APlayerController *PlayerController, const FBPUniqueNetId &FriendUniqueNetId, TEnumAsByte &Result); + + // Get a friend from the previously read/saved friends list (Must Call GetFriends first for this to return anything) + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedFriends|FriendsList") + static void GetFriend(APlayerController *PlayerController, const FBPUniqueNetId FriendUniqueNetId, FBPFriendInfo &Friend); + + // Get the previously read/saved friends list (Must Call GetFriends first for this to return anything) + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedFriends|FriendsList") + static void GetStoredFriendsList(APlayerController *PlayerController, TArray &FriendsList); + + // Get the previously read/saved recent players list (Must Call GetRecentPlayers first for this to return anything) + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedFriends|RecentPlayersList") + static void GetStoredRecentPlayersList(FBPUniqueNetId UniqueNetId, TArray &PlayersList); + + // Check if a UniqueNetId is a friend + UFUNCTION(BlueprintPure, Category = "Online|AdvancedFriends|FriendsList") + static void IsAFriend(APlayerController *PlayerController, const FBPUniqueNetId UniqueNetId, bool &IsFriend); + +}; diff --git a/Source/AdvancedSessions/Classes/AdvancedSessionsLibrary.h b/Source/AdvancedSessions/Classes/AdvancedSessionsLibrary.h new file mode 100644 index 0000000..021f064 --- /dev/null +++ b/Source/AdvancedSessions/Classes/AdvancedSessionsLibrary.h @@ -0,0 +1,143 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "OnlineSubSystemHeader.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Online.h" +#include "OnlineSubsystem.h" +#include "OnlineFriendsInterface.h" +#include "OnlineUserInterface.h" +#include "OnlineMessageInterface.h" +#include "OnlinePresenceInterface.h" +#include "Engine/GameInstance.h" +#include "OnlineSessionInterface.h" + +#include "UObjectIterator.h" + +#include "AdvancedSessionsLibrary.generated.h" + + +//General Advanced Sessions Log +DECLARE_LOG_CATEGORY_EXTERN(AdvancedSessionsLog, Log, All); + + +UCLASS() +class UAdvancedSessionsLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + //********* Session Search Functions *************// + + // Adds or modifies session settings in an existing array depending on if they exist already or not + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo") + static void AddOrModifyExtraSettings(const TArray & SettingsArray, const TArray & NewOrChangedSettings, TArray & ModifiedSettingsArray); + + // Get an array of the session settings from a session search result + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo") + static void GetExtraSettings(FBlueprintSessionResult SessionResult, TArray & ExtraSettings); + + // Get the current session state + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo") + static void GetSessionState(TEnumAsByte &SessionState); + + // Get the current session settings + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo", meta = (ExpandEnumAsExecs = "Result")) + static void GetSessionSettings(int32 &NumConnections, bool &bIsLAN, bool &bIsDedicated, bool &bIsAnticheatEnabled, int32 &BuildUniqueID, TArray &ExtraSettings, TEnumAsByte &Result); + + // Check if someone is in the current session + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo") + static void IsPlayerInSession(const FBPUniqueNetId &PlayerToCheck, bool &bIsInSession); + + // Make a literal session search parameter + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo|Literals") + static FSessionsSearchSetting MakeLiteralSessionSearchProperty(FSessionPropertyKeyPair SessionSearchProperty, EOnlineComparisonOpRedux::Type ComparisonOp); + + + //********* Session Information Functions ***********// + + // Get the Unique Current Build ID + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo") + static void GetCurrentUniqueBuildID(int32 &UniqueBuildId); + + // Get the Unique Build ID from a session search result + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo") + static void GetUniqueBuildID(FBlueprintSessionResult SessionResult, int32 &UniqueBuildId); + + // Get session custom information key/value as Byte (For Enums) + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo", meta = (ExpandEnumAsExecs = "SearchResult")) + static void GetSessionPropertyByte(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, uint8 &SettingValue); + + // Get session custom information key/value as Bool + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo", meta = (ExpandEnumAsExecs = "SearchResult")) + static void GetSessionPropertyBool(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, bool &SettingValue); + + // Get session custom information key/value as String + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo", meta = (ExpandEnumAsExecs = "SearchResult")) + static void GetSessionPropertyString(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, FString &SettingValue); + + // Get session custom information key/value as Int + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo", meta = (ExpandEnumAsExecs = "SearchResult")) + static void GetSessionPropertyInt(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, int32 &SettingValue); + + // Get session custom information key/value as Float + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|SessionInfo", meta = (ExpandEnumAsExecs = "SearchResult")) + static void GetSessionPropertyFloat(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, float &SettingValue); + + + // Make a literal session custom information key/value pair from Byte (For Enums) + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo|Literals") + static FSessionPropertyKeyPair MakeLiteralSessionPropertyByte(FName Key, uint8 Value); + + // Make a literal session custom information key/value pair from Bool + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo|Literals") + static FSessionPropertyKeyPair MakeLiteralSessionPropertyBool(FName Key, bool Value); + + // Make a literal session custom information key/value pair from String + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo|Literals") + static FSessionPropertyKeyPair MakeLiteralSessionPropertyString(FName Key, FString Value); + + // Make a literal session custom information key/value pair from Int + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo|Literals") + static FSessionPropertyKeyPair MakeLiteralSessionPropertyInt(FName Key, int32 Value); + + // Make a literal session custom information key/value pair from Float + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|SessionInfo|Literals") + static FSessionPropertyKeyPair MakeLiteralSessionPropertyFloat(FName Key, float Value); + + + //******* Player ID functions *********// + + // Get the unique net id of a network player attached to the given controller + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|PlayerInfo|PlayerID") + static void GetUniqueNetID(APlayerController *PlayerController, FBPUniqueNetId &UniqueNetId); + + // Check if a UniqueNetId is a friend + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|UniqueNetId") + static void UniqueNetIdToString(const FBPUniqueNetId &UniqueNetId, FString &String); + + //******** Player Name Functions **********// + + // Get the player name of a network player attached to the given controller + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|PlayerInfo|PlayerName") + static void GetPlayerName(APlayerController *PlayerController, FString &PlayerName); + + // Set the player name of a network player attached to the given controller + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSessions|PlayerInfo|PlayerName") + static void SetPlayerName(APlayerController *PlayerController, FString PlayerName); + + //********** Misc Player Info Functions *********// + + // Get the number of network players + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|PlayerInfo|Misc") + static void GetNumberOfNetworkPlayers(int32 &NumNetPlayers); + + // Get the network player index of the given controller + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|PlayerInfo|Misc") + static void GetNetPlayerIndex(APlayerController *PlayerController, int32 &NetPlayerIndex); + + // Checks if the stated session subsystem is active + UFUNCTION(BlueprintPure, Category = "Online|AdvancedSessions|Misc") + static bool HasOnlineSubsystem(FName SubSystemName); + + +}; diff --git a/Source/AdvancedSessions/Classes/AdvancedVoiceLibrary.h b/Source/AdvancedSessions/Classes/AdvancedVoiceLibrary.h new file mode 100644 index 0000000..76d37bc --- /dev/null +++ b/Source/AdvancedSessions/Classes/AdvancedVoiceLibrary.h @@ -0,0 +1,96 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "OnlineSubSystemHeader.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Online.h" +#include "OnlineSubsystem.h" +#include "VoiceInterface.h" +//#include "OnlineFriendsInterface.h" +//#include "OnlineUserInterface.h" +//#include "OnlineMessageInterface.h" +//#include "OnlinePresenceInterface.h" +#include "Engine/GameInstance.h" +//#include "OnlineSessionInterface.h" + +#include "UObjectIterator.h" + +#include "AdvancedVoiceLibrary.generated.h" + + +//General Advanced Sessions Log +DECLARE_LOG_CATEGORY_EXTERN(AdvancedVoiceLog, Log, All); + + +UCLASS() +class UAdvancedVoiceLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + + //********* Voice Library Functions *************// + + // Get if a headset is present for the specified local user + UFUNCTION(BlueprintPure, Category = "Online|AdvancedVoice|VoiceInfo") + static void IsHeadsetPresent(bool & bHasHeadset, uint8 LocalPlayerNum = 0); + + // Starts networked voice, allows push to talk in coordination with StopNetworkedVoice + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static void StartNetworkedVoice(uint8 LocalPlayerNum = 0); + + // Stops networked voice, allows push to talk in coordination with StartNetworkedVoice + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static void StopNetworkedVoice(uint8 LocalPlayerNum = 0); + + // Registers a local player as someone interested in voice data + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static bool RegisterLocalTalker(uint8 LocalPlayerNum = 0); + + // Registers all signed in players as local talkers + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static void RegisterAllLocalTalkers(); + + // UnRegisters local player as a local talker + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static void UnRegisterLocalTalker(uint8 LocalPlayerNum = 0); + + // UnRegisters all signed in players as local talkers + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static void UnRegisterAllLocalTalkers(); + + // Registers a remote player as a talker + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static bool RegisterRemoteTalker(const FBPUniqueNetId& UniqueNetId); + + // UnRegisters a remote player as a talker + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static bool UnRegisterRemoteTalker(const FBPUniqueNetId& UniqueNetId); + + // UnRegisters all remote players as talkers + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static void RemoveAllRemoteTalkers(); + + // Returns whether a local player is currently talking + UFUNCTION(BlueprintPure, Category = "Online|AdvancedVoice|VoiceInfo") + static bool IsLocalPlayerTalking(uint8 LocalPlayerNum); + + // Returns whether a remote player is currently talking + UFUNCTION(BlueprintPure, Category = "Online|AdvancedVoice|VoiceInfo") + static bool IsRemotePlayerTalking(const FBPUniqueNetId& UniqueNetId); + + // Returns whether a player is muted for the specified local player + UFUNCTION(BlueprintPure, Category = "Online|AdvancedVoice|VoiceInfo") + static bool IsPlayerMuted(uint8 LocalUserNumChecking, const FBPUniqueNetId& UniqueNetId); + + // Mutes the player associated with the uniquenetid for the specified local player, if IsSystemWide is true then it will attempt to mute globally for the player + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static bool MuteRemoteTalker(uint8 LocalUserNum, const FBPUniqueNetId& UniqueNetId, bool bIsSystemWide = false); + + // UnMutes the player associated with the uniquenetid for the specified local player, if IsSystemWide is true then it will attempt to unmute globally for the player + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedVoice") + static bool UnMuteRemoteTalker(uint8 LocalUserNum, const FBPUniqueNetId& UniqueNetId, bool bIsSystemWide = false); + + // Gets the number of local talkers for this system + UFUNCTION(BlueprintPure, Category = "Online|AdvancedVoice|VoiceInfo") + static void GetNumLocalTalkers(int32 & NumLocalTalkers); +}; diff --git a/Source/AdvancedSessions/Classes/CancelFindSessionsCallbackProxy.h b/Source/AdvancedSessions/Classes/CancelFindSessionsCallbackProxy.h new file mode 100644 index 0000000..afabc6f --- /dev/null +++ b/Source/AdvancedSessions/Classes/CancelFindSessionsCallbackProxy.h @@ -0,0 +1,44 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSessionInterface.h" +#include "CancelFindSessionsCallbackProxy.generated.h" + +UCLASS(MinimalAPI) +class UCancelFindSessionsCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when there is a successful destroy + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnSuccess; + + // Called when there is an unsuccessful destroy + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnFailure; + + // Cancels finding sessions + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedSessions") + static UCancelFindSessionsCallbackProxy* CancelFindSessions(UObject* WorldContextObject, class APlayerController* PlayerController); + + // UOnlineBlueprintCallProxyBase interface + virtual void Activate() override; + // End of UOnlineBlueprintCallProxyBase interface + +private: + // Internal callback when the operation completes, calls out to the public success/failure callbacks + void OnCompleted(bool bWasSuccessful); + +private: + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The delegate executed by the online subsystem + FOnCancelFindSessionsCompleteDelegate Delegate; + + // Handle to the registered OnDestroySessionComplete delegate + FDelegateHandle DelegateHandle; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; diff --git a/Source/AdvancedSessions/Classes/CreateSessionCallbackProxyAdvanced.h b/Source/AdvancedSessions/Classes/CreateSessionCallbackProxyAdvanced.h new file mode 100644 index 0000000..944b5c5 --- /dev/null +++ b/Source/AdvancedSessions/Classes/CreateSessionCallbackProxyAdvanced.h @@ -0,0 +1,67 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSubSystemHeader.h" + +#include "CreateSessionCallbackProxyAdvanced.generated.h" + +UCLASS(MinimalAPI) +class UCreateSessionCallbackProxyAdvanced : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when the session was created successfully + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnSuccess; + + // Called when there was an error creating the session + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnFailure; + + // Creates a session with the default online subsystem with advanced optional inputs + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject",AutoCreateRefTerm="ExtraSettings"), Category = "Online|AdvancedSessions") + static UCreateSessionCallbackProxyAdvanced* CreateAdvancedSession(UObject* WorldContextObject, const TArray &ExtraSettings, class APlayerController* PlayerController = NULL, int32 PublicConnections = 100, bool bUseLAN = false, bool bAllowInvites = true, bool bIsDedicatedServer = false); + + // UOnlineBlueprintCallProxyBase interface + virtual void Activate() override; + // End of UOnlineBlueprintCallProxyBase interface + +private: + // Internal callback when session creation completes, calls StartSession + void OnCreateCompleted(FName SessionName, bool bWasSuccessful); + + // Internal callback when session creation completes, calls StartSession + void OnStartCompleted(FName SessionName, bool bWasSuccessful); + + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The delegate executed by the online subsystem + FOnCreateSessionCompleteDelegate CreateCompleteDelegate; + + // The delegate executed by the online subsystem + FOnStartSessionCompleteDelegate StartCompleteDelegate; + + // Handles to the registered delegates above + FDelegateHandle CreateCompleteDelegateHandle; + FDelegateHandle StartCompleteDelegateHandle; + + // Number of public connections + int NumPublicConnections; + + // Whether or not to search LAN + bool bUseLAN; + + // Whether or not to allow invites + bool bAllowInvites; + + // Whether this is a dedicated server or not + bool bDedicatedServer; + + // Store extra settings + TArray ExtraSettings; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; + diff --git a/Source/AdvancedSessions/Classes/EndSessionCallbackProxy.h b/Source/AdvancedSessions/Classes/EndSessionCallbackProxy.h new file mode 100644 index 0000000..b9b6ece --- /dev/null +++ b/Source/AdvancedSessions/Classes/EndSessionCallbackProxy.h @@ -0,0 +1,44 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSessionInterface.h" +#include "EndSessionCallbackProxy.generated.h" + +UCLASS(MinimalAPI) +class UEndSessionCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when there is a successful destroy + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnSuccess; + + // Called when there is an unsuccessful destroy + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnFailure; + + // Ends the current session + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedSessions") + static UEndSessionCallbackProxy* EndSession(UObject* WorldContextObject, class APlayerController* PlayerController); + + // UOnlineBlueprintCallProxyBase interface + virtual void Activate() override; + // End of UOnlineBlueprintCallProxyBase interface + +private: + // Internal callback when the operation completes, calls out to the public success/failure callbacks + void OnCompleted(FName SessionName, bool bWasSuccessful); + +private: + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The delegate executed by the online subsystem + FOnEndSessionCompleteDelegate Delegate; + + // Handle to the registered OnDestroySessionComplete delegate + FDelegateHandle DelegateHandle; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; diff --git a/Source/AdvancedSessions/Classes/FindFriendSessionCallbackProxy.h b/Source/AdvancedSessions/Classes/FindFriendSessionCallbackProxy.h new file mode 100644 index 0000000..ccca32f --- /dev/null +++ b/Source/AdvancedSessions/Classes/FindFriendSessionCallbackProxy.h @@ -0,0 +1,50 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSubSystemHeader.h" + +#include "FindFriendSessionCallbackProxy.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(AdvancedFindFriendSessionLog, Log, All); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintFindFriendSessionDelegate, const FBlueprintSessionResult&, SessionInfo); + +UCLASS(MinimalAPI) +class UFindFriendSessionCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when the friends list successfully was retrieved + UPROPERTY(BlueprintAssignable) + FBlueprintFindFriendSessionDelegate OnSuccess; + + // Called when there was an error retrieving the friends list + UPROPERTY(BlueprintAssignable) + FBlueprintFindFriendSessionDelegate OnFailure; + + // Attempts to get the current session that a friend is in + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedFriends") + static UFindFriendSessionCallbackProxy* FindFriendSession(UObject* WorldContextObject, APlayerController *PlayerController, const FBPUniqueNetId &FriendUniqueNetId); + + virtual void Activate() override; + +private: + // Internal callback when the friends list is retrieved + void OnFindFriendSessionCompleted(int32 LocalPlayer, bool bWasSuccessful, const FOnlineSessionSearchResult& SessionInfo); + + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The UniqueNetID of the person to invite + FBPUniqueNetId cUniqueNetId; + + // The delegate to call on completion + FOnFindFriendSessionCompleteDelegate OnFindFriendSessionCompleteDelegate; + + // Handles to the registered delegates above + FDelegateHandle FindFriendSessionCompleteDelegateHandle; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; + diff --git a/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h b/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h new file mode 100644 index 0000000..09c914c --- /dev/null +++ b/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h @@ -0,0 +1,78 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSessionInterface.h" +#include "OnlineSubSystemHeader.h" +#include "FindSessionsCallbackProxy.h" +#include "FindSessionsCallbackProxyAdvanced.generated.h" + +UCLASS(MinimalAPI) +class UFindSessionsCallbackProxyAdvanced : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when there is a successful query + UPROPERTY(BlueprintAssignable) + FBlueprintFindSessionsResultDelegate OnSuccess; + + // Called when there is an unsuccessful query + UPROPERTY(BlueprintAssignable) + FBlueprintFindSessionsResultDelegate OnFailure; + + // Searches for advertised sessions with the default online subsystem and includes an array of filters + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", AutoCreateRefTerm="Filters"), Category = "Online|AdvancedSessions") + static UFindSessionsCallbackProxyAdvanced* FindSessionsAdvanced(UObject* WorldContextObject, class APlayerController* PlayerController, int32 MaxResults, bool bUseLAN, const TArray &Filters); + + static bool CompareVariants(const FVariantData &A, const FVariantData &B, EOnlineComparisonOpRedux::Type Comparator); + + // Filters an array of session results by the given search parameters, returns a new array with the filtered results + UFUNCTION(BluePrintCallable, meta = (Category = "Online|AdvancedSessions")) + static void FilterSessionResults(const TArray &SessionResults, const TArray &Filters, TArray &FilteredResults); + + // Removed, the default built in versions work fine in the normal FindSessionsCallbackProxy + /*UFUNCTION(BlueprintPure, Category = "Online|Session") + static int32 GetPingInMs(const FBlueprintSessionResult& Result); + + UFUNCTION(BlueprintPure, Category = "Online|Session") + static FString GetServerName(const FBlueprintSessionResult& Result); + + UFUNCTION(BlueprintPure, Category = "Online|Session") + static int32 GetCurrentPlayers(const FBlueprintSessionResult& Result); + + UFUNCTION(BlueprintPure, Category = "Online|Session") + static int32 GetMaxPlayers(const FBlueprintSessionResult& Result);*/ + + + // UOnlineBlueprintCallProxyBase interface + virtual void Activate() override; + // End of UOnlineBlueprintCallProxyBase interface + +private: + // Internal callback when the session search completes, calls out to the public success/failure callbacks + void OnCompleted(bool bSuccess); + +private: + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The delegate executed by the online subsystem + FOnFindSessionsCompleteDelegate Delegate; + + // Handle to the registered OnFindSessionsComplete delegate + FDelegateHandle DelegateHandle; + + // Object to track search results + TSharedPtr SearchObject; + + // Whether or not to search LAN + bool bUseLAN; + + // Maximum number of results to return + int MaxResults; + + // Store extra settings + TArray SearchSettings; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; diff --git a/Source/AdvancedSessions/Classes/GetFriendsCallbackProxy.h b/Source/AdvancedSessions/Classes/GetFriendsCallbackProxy.h new file mode 100644 index 0000000..1dfadbf --- /dev/null +++ b/Source/AdvancedSessions/Classes/GetFriendsCallbackProxy.h @@ -0,0 +1,48 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSubSystemHeader.h" + +#include "GetFriendsCallbackProxy.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(AdvancedGetFriendsLog, Log, All); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintGetFriendsListDelegate, const TArray&, Results); + +UCLASS(MinimalAPI) +class UGetFriendsCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when the friends list successfully was retrieved + UPROPERTY(BlueprintAssignable) + FBlueprintGetFriendsListDelegate OnSuccess; + + // Called when there was an error retrieving the friends list + UPROPERTY(BlueprintAssignable) + FBlueprintGetFriendsListDelegate OnFailure; + + // Gets the players list of friends from the OnlineSubsystem and returns it, can be retrieved later with GetStoredFriendsList + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedFriends") + static UGetFriendsCallbackProxy* GetAndStoreFriendsList(UObject* WorldContextObject, class APlayerController* PlayerController); + + virtual void Activate() override; + +private: + // Internal callback when the friends list is retrieved + void OnReadFriendsListCompleted(int32 LocalUserNum, bool bWasSuccessful, const FString& ListName, const FString& ErrorString); + + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The delegate executed + FOnReadFriendsListComplete FriendListReadCompleteDelegate; + + // The Type of friends list to get + // Removed because all but the facebook interfaces don't even currently support anything but the default friends list. + //EBPFriendsLists::Type FriendListToGet; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; + diff --git a/Source/AdvancedSessions/Classes/GetRecentPlayersCallbackProxy.h b/Source/AdvancedSessions/Classes/GetRecentPlayersCallbackProxy.h new file mode 100644 index 0000000..aaa2897 --- /dev/null +++ b/Source/AdvancedSessions/Classes/GetRecentPlayersCallbackProxy.h @@ -0,0 +1,49 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSubSystemHeader.h" + +#include "GetRecentPlayersCallbackProxy.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(AdvancedGetRecentPlayersLog, Log, All); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintGetRecentPlayersDelegate, const TArray&, Results); + +UCLASS(MinimalAPI) +class UGetRecentPlayersCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when the friends list successfully was retrieved + UPROPERTY(BlueprintAssignable) + FBlueprintGetRecentPlayersDelegate OnSuccess; + + // Called when there was an error retrieving the friends list + UPROPERTY(BlueprintAssignable) + FBlueprintGetRecentPlayersDelegate OnFailure; + + // Gets the list of recent players from the OnlineSubsystem and returns it, can be retrieved later with GetStoredRecentPlayersList, can fail if no recent players are found + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedFriends") + static UGetRecentPlayersCallbackProxy* GetAndStoreRecentPlayersList(UObject* WorldContextObject, const FBPUniqueNetId &UniqueNetId); + + virtual void Activate() override; + +private: + // Internal callback when the friends list is retrieved + void OnQueryRecentPlayersCompleted(const FUniqueNetId &UserID, const FString &Namespace, bool bWasSuccessful, const FString& ErrorString); + // Handle to the registered OnFindSessionsComplete delegate + FDelegateHandle DelegateHandle; + + // The player controller triggering things + //TWeakObjectPtr PlayerControllerWeakPtr; + + // The UniqueNetID of the person to get recent players for + FBPUniqueNetId cUniqueNetId; + + // The delegate executed + FOnQueryRecentPlayersCompleteDelegate QueryRecentPlayersCompleteDelegate; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; + diff --git a/Source/AdvancedSessions/Classes/SendFriendInviteCallbackProxy.h b/Source/AdvancedSessions/Classes/SendFriendInviteCallbackProxy.h new file mode 100644 index 0000000..323de53 --- /dev/null +++ b/Source/AdvancedSessions/Classes/SendFriendInviteCallbackProxy.h @@ -0,0 +1,48 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSubSystemHeader.h" + +#include "SendFriendInviteCallbackProxy.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(AdvancedSendFriendInviteLog, Log, All); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FBlueprintSendFriendInviteDelegate); + +UCLASS(MinimalAPI) +class USendFriendInviteCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when the friends list successfully was retrieved + UPROPERTY(BlueprintAssignable) + FBlueprintSendFriendInviteDelegate OnSuccess; + + // Called when there was an error retrieving the friends list + UPROPERTY(BlueprintAssignable) + FBlueprintSendFriendInviteDelegate OnFailure; + + // Adds a friend who is using the defined UniqueNetId, some interfaces do now allow this function to be called (INCLUDING STEAM) + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedFriends") + static USendFriendInviteCallbackProxy* SendFriendInvite(UObject* WorldContextObject, APlayerController *PlayerController, const FBPUniqueNetId &UniqueNetIDInvited); + + virtual void Activate() override; + +private: + // Internal callback when the friends list is retrieved + void OnSendInviteComplete(int32 LocalPlayerNum, bool bWasSuccessful, const FUniqueNetId &InvitedPlayer, const FString &ListName, const FString &ErrorString); + + + // The player controller triggering things + TWeakObjectPtr PlayerControllerWeakPtr; + + // The UniqueNetID of the person to invite + FBPUniqueNetId cUniqueNetId; + + // The delegate to call on completion + FOnSendInviteComplete OnSendInviteCompleteDelegate; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; + diff --git a/Source/AdvancedSessions/Classes/UpdateSessionCallbackProxyAdvanced.h b/Source/AdvancedSessions/Classes/UpdateSessionCallbackProxyAdvanced.h new file mode 100644 index 0000000..e447b80 --- /dev/null +++ b/Source/AdvancedSessions/Classes/UpdateSessionCallbackProxyAdvanced.h @@ -0,0 +1,63 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "OnlineSubSystemHeader.h" + +#include "UpdateSessionCallbackProxyAdvanced.generated.h" + +UCLASS(MinimalAPI) +class UUpdateSessionCallbackProxyAdvanced : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when the session was updated successfully + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnSuccess; + + // Called when there was an error updating the session + UPROPERTY(BlueprintAssignable) + FEmptyOnlineDelegate OnFailure; + + // Creates a session with the default online subsystem with advanced optional inputs + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject",AutoCreateRefTerm="ExtraSettings"), Category = "Online|AdvancedSessions") + static UUpdateSessionCallbackProxyAdvanced* UpdateSession(UObject* WorldContextObject, int32 PublicConnections, bool bUseLAN, bool bAllowInvites, bool bAllowJoinInProgress, const TArray &ExtraSettings, bool bRefreshOnlineData = true, bool bIsDedicatedServer = false); + + // UOnlineBlueprintCallProxyBase interface + virtual void Activate() override; + // End of UOnlineBlueprintCallProxyBase interface + +private: + // Internal callback when session creation completes, calls StartSession + void OnUpdateCompleted(FName SessionName, bool bWasSuccessful); + + // The delegate executed by the online subsystem + FOnUpdateSessionCompleteDelegate OnUpdateSessionCompleteDelegate; + + // Handles to the registered delegates above + FDelegateHandle OnUpdateSessionCompleteDelegateHandle; + + // Number of public connections + int NumPublicConnections; + + // Whether or not to search LAN + bool bUseLAN; + + // Whether or not to allow invites + bool bAllowInvites; + + // Store extra settings + TArray ExtraSettings; + + // Whether to update the online data + bool bRefreshOnlineData; + + // Allow joining in progress + bool bAllowJoinInProgress; + + // Update whether this is a dedicated server or not + bool bDedicatedServer; + + // The world context object in which this call is taking place + UObject* WorldContextObject; +}; + diff --git a/Source/AdvancedSessions/Private/AdvancedFriendsGameInstance.cpp b/Source/AdvancedSessions/Private/AdvancedFriendsGameInstance.cpp new file mode 100644 index 0000000..8d632a2 --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedFriendsGameInstance.cpp @@ -0,0 +1,196 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "AdvancedFriendsGameInstance.h" + +//General Log +DEFINE_LOG_CATEGORY(AdvancedFriendsInterfaceLog); + +UAdvancedFriendsGameInstance::UAdvancedFriendsGameInstance(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , SessionInviteAcceptedDelegate(FOnSessionUserInviteAcceptedDelegate::CreateUObject(this, &ThisClass::OnSessionInviteAcceptedMaster)) + , bCallFriendInterfaceEventsOnPlayerControllers(true) + , PlayerTalkingStateChangedDelegate(FOnPlayerTalkingStateChangedDelegate::CreateUObject(this, &ThisClass::OnPlayerTalkingStateChangedMaster)) + , bEnableTalkingStatusDelegate(true) + , bCallVoiceInterfaceEventsOnPlayerControllers(true) +{ +} + +void UAdvancedFriendsGameInstance::Shutdown() +{ + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(); + + if (!SessionInterface.IsValid()) + { + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsGameInstance Failed to get session system!")); + //return; + } + else + { + // Clear all of the delegate handles here + SessionInterface->ClearOnSessionUserInviteAcceptedDelegate_Handle(SessionInviteAcceptedDelegateHandle); + + } + + + if (bEnableTalkingStatusDelegate) + { + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (VoiceInterface.IsValid()) + { + VoiceInterface->ClearOnPlayerTalkingStateChangedDelegate_Handle(PlayerTalkingStateChangedDelegateHandle); + } + else + { + + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsInstance Failed to get voice interface!")); + } + } + + Super::Shutdown(); +} + +void UAdvancedFriendsGameInstance::Init() +{ + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface();//OnlineSub->GetSessionInterface(); + + if (SessionInterface.IsValid()) + { + // Currently doesn't store a handle or assign a delegate to any local player beyond the first.....should handle? + // Thought about directly handling it but friends for multiple players probably isn't required + // Iterating through the local player TArray only works if it has had players assigned to it, most of the online interfaces don't support + // Multiple logins either (IE: Steam) + SessionInviteAcceptedDelegateHandle = SessionInterface->AddOnSessionUserInviteAcceptedDelegate_Handle(SessionInviteAcceptedDelegate); + + } + else + { + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsInstance Failed to get session interface!")); + //return; + } + + // Beginning work on the voice interface + if (bEnableTalkingStatusDelegate) + { + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (VoiceInterface.IsValid()) + { + PlayerTalkingStateChangedDelegateHandle = VoiceInterface->AddOnPlayerTalkingStateChangedDelegate_Handle(PlayerTalkingStateChangedDelegate); + } + else + { + + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsInstance Failed to get voice interface!")); + } + } + + Super::Init(); +} + +/*void UAdvancedFriendsGameInstance::PostLoad() +{ + Super::PostLoad(); +}*/ + + +// Removed because it never gets called by the online subsystems +/*void UAdvancedFriendsGameInstance::OnSessionInviteReceivedMaster(const FUniqueNetId &InvitedPlayer, const FUniqueNetId &FriendInviting, const FOnlineSessionSearchResult& Session) +{ + // Just call the blueprint event to let the user handle this + + FBPUniqueNetId IP, FI; + + IP.SetUniqueNetId(&InvitedPlayer); + + FI.SetUniqueNetId(&FriendInviting); + + FBlueprintSessionResult BPS; + BPS.OnlineResult = Session; + OnSessionInviteReceived(IP,FI,BPS); + + TArray& PlayerArray = GetWorld()->GetGameState()->PlayerArray; + const TArray&ControllerArray = this->GetLocalPlayers(); + + for (int i = 0; i < ControllerArray.Num(); i++) + { + if (*PlayerArray[ControllerArray[i]->PlayerController->NetPlayerIndex]->UniqueId.GetUniqueNetId().Get() == InvitedPlayer) + { + //Run the Event specific to the actor, if the actor has the interface, otherwise ignore + if (ControllerArray[i]->PlayerController->GetClass()->ImplementsInterface(UAdvancedFriendsInterface::StaticClass())) + { + IAdvancedFriendsInterface::Execute_OnSessionInviteReceived(ControllerArray[i]->PlayerController, FI, BPS); + } + break; + } + } +}*/ + +void UAdvancedFriendsGameInstance::OnPlayerTalkingStateChangedMaster(TSharedRef PlayerId, bool bIsTalking) +{ + FBPUniqueNetId PlayerTalking; + PlayerTalking.SetUniqueNetId(PlayerId); + OnPlayerTalkingStateChanged(PlayerTalking, bIsTalking); + + if (bCallVoiceInterfaceEventsOnPlayerControllers) + { + APlayerController* Player = NULL; + + for (const ULocalPlayer* LPlayer : LocalPlayers) + { + Player = UGameplayStatics::GetPlayerController(GetWorld(), LPlayer->GetControllerId()); + + if (Player != NULL) + { + //Run the Event specific to the actor, if the actor has the interface, otherwise ignore + if (Player->GetClass()->ImplementsInterface(UAdvancedFriendsInterface::StaticClass())) + { + IAdvancedFriendsInterface::Execute_OnPlayerVoiceStateChanged(Player, PlayerTalking, bIsTalking); + } + } + else + { + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsInstance Failed to get a controller with the specified index in OnVoiceStateChanged!")); + } + } + } +} + +void UAdvancedFriendsGameInstance::OnSessionInviteAcceptedMaster(const bool bWasSuccessful, int32 LocalPlayer, TSharedPtr PersonInviting, const FOnlineSessionSearchResult& SessionToJoin) +{ + if (bWasSuccessful) + { + if (SessionToJoin.IsValid()) + { + + FBlueprintSessionResult BluePrintResult; + BluePrintResult.OnlineResult = SessionToJoin; + + FBPUniqueNetId PInviting; + PInviting.SetUniqueNetId(PersonInviting); + + OnSessionInviteAccepted(LocalPlayer,PInviting, BluePrintResult); + + APlayerController* Player = UGameplayStatics::GetPlayerController(GetWorld(), LocalPlayer); + + IAdvancedFriendsInterface* TheInterface = NULL; + + if (Player != NULL) + { + //Run the Event specific to the actor, if the actor has the interface, otherwise ignore + if (Player->GetClass()->ImplementsInterface(UAdvancedFriendsInterface::StaticClass())) + { + IAdvancedFriendsInterface::Execute_OnSessionInviteAccepted(Player,PInviting, BluePrintResult); + } + } + else + { + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsInstance Failed to get a controller with the specified index in OnSessionInviteAccepted!")); + } + } + else + { + UE_LOG(AdvancedFriendsInterfaceLog, Warning, TEXT("UAdvancedFriendsInstance Return a bad search result in OnSessionInviteAccepted!")); + } + } +} \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/AdvancedFriendsInterface.cpp b/Source/AdvancedSessions/Private/AdvancedFriendsInterface.cpp new file mode 100644 index 0000000..0468aa1 --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedFriendsInterface.cpp @@ -0,0 +1,9 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "AdvancedFriendsInterface.h" + + +UAdvancedFriendsInterface::UAdvancedFriendsInterface(const class FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} diff --git a/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp b/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp new file mode 100644 index 0000000..1ed58ba --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp @@ -0,0 +1,251 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "AdvancedFriendsLibrary.h" + +//General Log +DEFINE_LOG_CATEGORY(AdvancedFriendsLog); + +void UAdvancedFriendsLibrary::SendSessionInviteToFriends(APlayerController *PlayerController, const TArray &Friends, TEnumAsByte &Result) +{ + if (!PlayerController) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend Had a bad Player Controller!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + if (Friends.Num() < 1) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend Had no friends in invitation array!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(); + + if (!SessionInterface.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend Failed to get session interface!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + ULocalPlayer* Player = Cast(PlayerController->Player); + + if (!Player) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend failed to get LocalPlayer!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + TArray> List; + for (int i = 0; i < Friends.Num(); i++) + { + TSharedRef val(Friends[i].UniqueNetId.ToSharedRef()); + //TSharedRef val(Friends[i].GetUniqueNetId()); + List.Add(val); + } + + if (SessionInterface->SendSessionInviteToFriends(Player->GetControllerId(), GameSessionName, List)) + { + Result = EBlueprintResultSwitch::Type::OnSuccess; + return; + } + + Result = EBlueprintResultSwitch::Type::OnFailure; + return; +} + +void UAdvancedFriendsLibrary::SendSessionInviteToFriend(APlayerController *PlayerController, const FBPUniqueNetId &FriendUniqueNetId, TEnumAsByte &Result) +{ + if (!PlayerController) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend Had a bad Player Controller!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + if (!FriendUniqueNetId.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend Had a bad UniqueNetId!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(); + + if (!SessionInterface.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend Failed to get session interface!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + ULocalPlayer* Player = Cast(PlayerController->Player); + + if (!Player) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("SendSessionInviteToFriend failed to get LocalPlayer!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + if (SessionInterface->SendSessionInviteToFriend(Player->GetControllerId(), GameSessionName, *FriendUniqueNetId.GetUniqueNetId())) + { + Result = EBlueprintResultSwitch::Type::OnSuccess; + return; + } + + Result = EBlueprintResultSwitch::Type::OnFailure; + return; +} + +void UAdvancedFriendsLibrary::GetFriend(APlayerController *PlayerController, const FBPUniqueNetId FriendUniqueNetId, FBPFriendInfo &Friend) +{ + + if (!PlayerController) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriend Had a bad Player Controller!")); + return; + } + + if (!FriendUniqueNetId.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriend Had a bad UniqueNetId!")); + return; + } + + IOnlineFriendsPtr FriendsInterface = Online::GetFriendsInterface(); + + if (!FriendsInterface.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriend Failed to get friends interface!")); + return; + } + + ULocalPlayer* Player = Cast(PlayerController->Player); + + if (!Player) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriend failed to get LocalPlayer!")); + return; + } + + TSharedPtr fr = FriendsInterface->GetFriend(Player->GetControllerId(), *FriendUniqueNetId.GetUniqueNetId(), EFriendsLists::ToString(EFriendsLists::Type::Default)); + if (fr.IsValid()) + { + Friend.DisplayName = fr->GetDisplayName(); + Friend.OnlineState = ((EBPOnlinePresenceState::Type)((int32)fr->GetPresence().Status.State)); + Friend.RealName = fr->GetRealName(); + Friend.UniqueNetId.SetUniqueNetId(fr->GetUserId()); + Friend.bIsPlayingSameGame = fr->GetPresence().bIsPlayingThisGame; + } +} + +void UAdvancedFriendsLibrary::IsAFriend(APlayerController *PlayerController, const FBPUniqueNetId UniqueNetId, bool &IsFriend) +{ + if (!PlayerController) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("IsAFriend Had a bad Player Controller!")); + return; + } + + if (!UniqueNetId.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("IsAFriend Had a bad UniqueNetId!")); + return; + } + + IOnlineFriendsPtr FriendsInterface = Online::GetFriendsInterface(); + + if (!FriendsInterface.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("IsAFriend Failed to get friends interface!")); + return; + } + + ULocalPlayer* Player = Cast(PlayerController->Player); + + if (!Player) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("IsAFriend Failed to get LocalPlayer!")); + return; + } + + IsFriend = FriendsInterface->IsFriend(Player->GetControllerId(), *UniqueNetId.GetUniqueNetId(), EFriendsLists::ToString(EFriendsLists::Type::Default)); +} + +void UAdvancedFriendsLibrary::GetStoredRecentPlayersList(FBPUniqueNetId UniqueNetId, TArray &PlayersList) +{ + IOnlineFriendsPtr FriendsInterface = Online::GetFriendsInterface(); + + if (!FriendsInterface.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetRecentPlayersList Failed to get friends interface!")); + return; + } + + if (!UniqueNetId.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetRecentPlayersList Failed was given an invalid UniqueNetId!")); + return; + } + + TArray< TSharedRef > PlayerList; + + // For now getting all namespaces + FriendsInterface->GetRecentPlayers(*(UniqueNetId.GetUniqueNetId()),"", PlayerList); + + for (int32 i = 0; i < PlayerList.Num(); i++) + { + TSharedRef Player = PlayerList[i]; + FBPOnlineRecentPlayer BPF; + BPF.DisplayName = Player->GetDisplayName(); + BPF.RealName = Player->GetRealName(); + BPF.UniqueNetId.SetUniqueNetId(Player->GetUserId()); + PlayersList.Add(BPF); + } +} + +void UAdvancedFriendsLibrary::GetStoredFriendsList(APlayerController *PlayerController, TArray &FriendsList) +{ + + if (!PlayerController) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriendsList Had a bad Player Controller!")); + return; + } + + IOnlineFriendsPtr FriendsInterface = Online::GetFriendsInterface(); + + if (!FriendsInterface.IsValid()) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriendsList Failed to get friends interface!")); + return; + } + + ULocalPlayer* Player = Cast(PlayerController->Player); + + if (!Player) + { + UE_LOG(AdvancedFriendsLog, Warning, TEXT("GetFriendsList Failed to get LocalPlayer!")); + return; + } + + + TArray< TSharedRef > FriendList; + FriendsInterface->GetFriendsList(Player->GetControllerId(), EFriendsLists::ToString((EFriendsLists::Type::Default)), FriendList); + + for (int32 i = 0; i < FriendList.Num(); i++) + { + TSharedRef Friend = FriendList[i]; + FBPFriendInfo BPF; + + BPF.OnlineState = ((EBPOnlinePresenceState::Type)((int32)Friend->GetPresence().Status.State)); + BPF.DisplayName = Friend->GetDisplayName(); + BPF.RealName = Friend->GetRealName(); + BPF.UniqueNetId.SetUniqueNetId(Friend->GetUserId()); + FriendsList.Add(BPF); + } +} \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/AdvancedSessions.cpp b/Source/AdvancedSessions/Private/AdvancedSessions.cpp new file mode 100644 index 0000000..e6630a8 --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedSessions.cpp @@ -0,0 +1,13 @@ +//#include "StandAlonePrivatePCH.h" +#include "OnlineSubSystemHeader.h" +#include "AdvancedSessions.h" + +void AdvancedSessions::StartupModule() +{ +} + +void AdvancedSessions::ShutdownModule() +{ +} + +IMPLEMENT_MODULE(AdvancedSessions, AdvancedSessions) \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/AdvancedSessions.h b/Source/AdvancedSessions/Private/AdvancedSessions.h new file mode 100644 index 0000000..c2cbeec --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedSessions.h @@ -0,0 +1,12 @@ +#pragma once + +#include "OnlineSubSystemHeader.h" +#include "ModuleManager.h" + +class AdvancedSessions : public IModuleInterface +{ +public: + /** IModuleInterface implementation */ + void StartupModule(); + void ShutdownModule(); +}; \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/AdvancedSessionsLibrary.cpp b/Source/AdvancedSessions/Private/AdvancedSessionsLibrary.cpp new file mode 100644 index 0000000..be629bf --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedSessionsLibrary.cpp @@ -0,0 +1,397 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "AdvancedSessionsLibrary.h" + +//General Log +DEFINE_LOG_CATEGORY(AdvancedSessionsLog); + +void UAdvancedSessionsLibrary::GetCurrentUniqueBuildID(int32 &UniqueBuildId) +{ + UniqueBuildId = GetBuildUniqueId(); +} + +void UAdvancedSessionsLibrary::GetUniqueBuildID(FBlueprintSessionResult SessionResult, int32 &UniqueBuildId) +{ + UniqueBuildId = SessionResult.OnlineResult.Session.SessionSettings.BuildUniqueId; +} + +void UAdvancedSessionsLibrary::AddOrModifyExtraSettings(const TArray & SettingsArray, const TArray & NewOrChangedSettings, TArray & ModifiedSettingsArray) +{ + ModifiedSettingsArray = SettingsArray; + + bool bFoundSetting = false; + // For each new setting + for (const FSessionPropertyKeyPair& Setting : NewOrChangedSettings) + { + bFoundSetting = false; + + for (FSessionPropertyKeyPair itr : ModifiedSettingsArray) + { + // Manually comparing the keys + if (itr.Key == Setting.Key) + { + bFoundSetting = true; + itr.Data = Setting.Data; + } + } + + // If it was not found, add to the array instead + if (!bFoundSetting) + { + ModifiedSettingsArray.Add(Setting); + } + } + +} + +void UAdvancedSessionsLibrary::GetExtraSettings(FBlueprintSessionResult SessionResult, TArray & ExtraSettings) +{ + FSessionPropertyKeyPair NewSetting; + for (auto& Elem : SessionResult.OnlineResult.Session.SessionSettings.Settings) + { + NewSetting.Key = Elem.Key; + NewSetting.Data = Elem.Value.Data; + ExtraSettings.Add(NewSetting); + } +} + +void UAdvancedSessionsLibrary::GetSessionState(TEnumAsByte &SessionState) +{ + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(); + + if (!SessionInterface.IsValid()) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetSessionState couldn't get the session interface!")); + return; + } + + SessionState = ((EBPOnlineSessionState::Type)SessionInterface->GetSessionState(GameSessionName)); +} + +void UAdvancedSessionsLibrary::GetSessionSettings(int32 &NumConnections, bool &bIsLAN, bool &bIsDedicated, bool &bIsAnticheatEnabled, int32 &BuildUniqueID, TArray &ExtraSettings, TEnumAsByte &Result) +{ + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(); + + if (!SessionInterface.IsValid()) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetSessionSettings couldn't get the session interface!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + + FOnlineSessionSettings* settings = SessionInterface->GetSessionSettings(GameSessionName); + if (!settings) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetSessionSettings couldn't get the session settings!")); + Result = EBlueprintResultSwitch::Type::OnFailure; + return; + } + BuildUniqueID = settings->BuildUniqueId; + NumConnections = settings->NumPublicConnections; + bIsLAN = settings->bIsLANMatch; + bIsDedicated = settings->bIsDedicated; + bIsAnticheatEnabled = settings->bAntiCheatProtected; + + FSessionPropertyKeyPair NewSetting; + + for (auto& Elem : settings->Settings) + { + NewSetting.Key = Elem.Key; + NewSetting.Data = Elem.Value.Data; + ExtraSettings.Add(NewSetting); + } + + Result = EBlueprintResultSwitch::Type::OnSuccess; +} + +void UAdvancedSessionsLibrary::IsPlayerInSession(const FBPUniqueNetId &PlayerToCheck, bool &bIsInSession) +{ + IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(); + + if (!SessionInterface.IsValid()) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("IsPlayerInSession couldn't get the session interface!")); + bIsInSession = false; + return; + } + + bIsInSession = SessionInterface->IsPlayerInSession(GameSessionName, *PlayerToCheck.GetUniqueNetId()); +} + +FSessionsSearchSetting UAdvancedSessionsLibrary::MakeLiteralSessionSearchProperty(FSessionPropertyKeyPair SessionSearchProperty, EOnlineComparisonOpRedux::Type ComparisonOp) +{ + FSessionsSearchSetting setting; + setting.PropertyKeyPair = SessionSearchProperty; + setting.ComparisonOp = ComparisonOp; + + return setting; +} + +FSessionPropertyKeyPair UAdvancedSessionsLibrary::MakeLiteralSessionPropertyByte(FName Key, uint8 Value) +{ + FSessionPropertyKeyPair Prop; + Prop.Key = Key; + Prop.Data.SetValue((int32)Value); + return Prop; +} + +FSessionPropertyKeyPair UAdvancedSessionsLibrary::MakeLiteralSessionPropertyBool(FName Key, bool Value) +{ + FSessionPropertyKeyPair Prop; + Prop.Key = Key; + Prop.Data.SetValue(Value); + return Prop; +} + +FSessionPropertyKeyPair UAdvancedSessionsLibrary::MakeLiteralSessionPropertyString(FName Key, FString Value) +{ + FSessionPropertyKeyPair Prop; + Prop.Key = Key; + Prop.Data.SetValue(Value); + return Prop; +} + +FSessionPropertyKeyPair UAdvancedSessionsLibrary::MakeLiteralSessionPropertyInt(FName Key, int32 Value) +{ + FSessionPropertyKeyPair Prop; + Prop.Key = Key; + Prop.Data.SetValue(Value); + return Prop; +} + +FSessionPropertyKeyPair UAdvancedSessionsLibrary::MakeLiteralSessionPropertyFloat(FName Key, float Value) +{ + FSessionPropertyKeyPair Prop; + Prop.Key = Key; + Prop.Data.SetValue(Value); + return Prop; +} + +void UAdvancedSessionsLibrary::GetSessionPropertyByte(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, uint8 &SettingValue) +{ + for (FSessionPropertyKeyPair itr : ExtraSettings) + { + if (itr.Key == SettingName) + { + if (itr.Data.GetType() == EOnlineKeyValuePairDataType::Int32) + { + int32 Val; + itr.Data.GetValue(Val); + SettingValue = (uint8)(Val); + SearchResult = ESessionSettingSearchResult::Type::Found; + } + else + { + SearchResult = ESessionSettingSearchResult::Type::WrongType; + } + return; + } + } + + SearchResult = ESessionSettingSearchResult::Type::NotFound; + return; +} + +void UAdvancedSessionsLibrary::GetSessionPropertyBool(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, bool &SettingValue) +{ + for (FSessionPropertyKeyPair itr : ExtraSettings) + { + if (itr.Key == SettingName) + { + if (itr.Data.GetType() == EOnlineKeyValuePairDataType::Bool) + { + itr.Data.GetValue(SettingValue); + SearchResult = ESessionSettingSearchResult::Type::Found; + } + else + { + SearchResult = ESessionSettingSearchResult::Type::WrongType; + } + return; + } + } + + SearchResult = ESessionSettingSearchResult::Type::NotFound; + return; +} + +void UAdvancedSessionsLibrary::GetSessionPropertyString(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, FString &SettingValue) +{ + for (FSessionPropertyKeyPair itr : ExtraSettings) + { + if (itr.Key == SettingName) + { + if (itr.Data.GetType() == EOnlineKeyValuePairDataType::String) + { + itr.Data.GetValue(SettingValue); + SearchResult = ESessionSettingSearchResult::Type::Found; + } + else + { + SearchResult = ESessionSettingSearchResult::Type::WrongType; + } + return; + } + } + + SearchResult = ESessionSettingSearchResult::Type::NotFound; + return; +} + +void UAdvancedSessionsLibrary::GetSessionPropertyInt(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, int32 &SettingValue) +{ + for (FSessionPropertyKeyPair itr : ExtraSettings) + { + if (itr.Key == SettingName) + { + if (itr.Data.GetType() == EOnlineKeyValuePairDataType::Int32) + { + itr.Data.GetValue(SettingValue); + SearchResult = ESessionSettingSearchResult::Type::Found; + } + else + { + SearchResult = ESessionSettingSearchResult::Type::WrongType; + } + return; + } + } + + SearchResult = ESessionSettingSearchResult::Type::NotFound; + return; +} + +void UAdvancedSessionsLibrary::GetSessionPropertyFloat(const TArray & ExtraSettings, FName SettingName, TEnumAsByte &SearchResult, float &SettingValue) +{ + for (FSessionPropertyKeyPair itr : ExtraSettings) + { + if (itr.Key == SettingName) + { + if (itr.Data.GetType() == EOnlineKeyValuePairDataType::Float) + { + itr.Data.GetValue(SettingValue); + SearchResult = ESessionSettingSearchResult::Type::Found; + } + else + { + SearchResult = ESessionSettingSearchResult::Type::WrongType; + } + return; + } + } + + SearchResult = ESessionSettingSearchResult::Type::NotFound; + return; +} + + +bool UAdvancedSessionsLibrary::HasOnlineSubsystem(FName SubSystemName) +{ + return((IOnlineSubsystem::Get(SubSystemName) != NULL)); +} + +void UAdvancedSessionsLibrary::GetNetPlayerIndex(APlayerController *PlayerController, int32 &NetPlayerIndex) +{ + if (!PlayerController) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetNetPlayerIndex received a bad PlayerController!")); + NetPlayerIndex = 0; + return; + } + + NetPlayerIndex = PlayerController->NetPlayerIndex; + return; +} + +void UAdvancedSessionsLibrary::UniqueNetIdToString(const FBPUniqueNetId& UniqueNetId, FString &String) +{ + const FUniqueNetId * ID = UniqueNetId.GetUniqueNetId(); + + if ( !ID ) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("UniqueNetIdToString received a bad UniqueNetId!")); + String = "ERROR, BAD UNIQUE NET ID"; + } + + String = ID->ToString(); +} + + +void UAdvancedSessionsLibrary::GetUniqueNetID(APlayerController *PlayerController, FBPUniqueNetId &UniqueNetId) +{ + if (!PlayerController) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetUniqueNetIdFromController received a bad PlayerController!")); + return; + } + + if (APlayerState* PlayerState = (PlayerController != NULL) ? PlayerController->PlayerState : NULL) + { + UniqueNetId.SetUniqueNetId(PlayerState->UniqueId.GetUniqueNetId()); + if (!UniqueNetId.IsValid()) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetUniqueNetIdFromController couldn't get the player uniquenetid!")); + } + return; + } +} + +void UAdvancedSessionsLibrary::SetPlayerName(APlayerController *PlayerController, FString PlayerName) +{ + if (!PlayerController) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("SetLocalPlayerNameFromController Bad Player Controller!")); + return; + } + + if (APlayerState* PlayerState = (PlayerController != NULL) ? PlayerController->PlayerState : NULL) + { + PlayerState->SetPlayerName(PlayerName); + return; + } + else + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("SetLocalPlayerNameFromController had a bad player state!")); + } +} + +void UAdvancedSessionsLibrary::GetPlayerName(APlayerController *PlayerController, FString &PlayerName) +{ + if (!PlayerController) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetLocalPlayerNameFromController Bad Player Controller!")); + return; + } + + if (APlayerState* PlayerState = (PlayerController != NULL) ? PlayerController->PlayerState : NULL) + { + PlayerName = PlayerState->PlayerName; + return; + } + else + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetLocalPlayerNameFromController had a bad player state!")); + } +} + +void UAdvancedSessionsLibrary::GetNumberOfNetworkPlayers(int32 &NumNetPlayers) +{ + //Get an actor to GetWorld() from + TObjectIterator Itr; + if (!Itr) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetNumberOfNetworkPlayers Failed to get iterator!")); + return; + } + //~~~~~~~~~~~~ + + //Get World + UWorld* TheWorld = Itr->GetWorld(); + if (!TheWorld) + { + UE_LOG(AdvancedSessionsLog, Warning, TEXT("GetNumberOfNetworkPlayers Failed to get World()!")); + return; + } + TArray& PlayerArray = (TheWorld->GetGameState()->PlayerArray); + NumNetPlayers = PlayerArray.Num(); +} diff --git a/Source/AdvancedSessions/Private/AdvancedVoiceLibrary.cpp b/Source/AdvancedSessions/Private/AdvancedVoiceLibrary.cpp new file mode 100644 index 0000000..fc1b7ea --- /dev/null +++ b/Source/AdvancedSessions/Private/AdvancedVoiceLibrary.cpp @@ -0,0 +1,218 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "AdvancedVoiceLibrary.h" + +//General Log +DEFINE_LOG_CATEGORY(AdvancedVoiceLog); + +void UAdvancedVoiceLibrary::IsHeadsetPresent(bool & bHasHeadset, uint8 LocalPlayerNum) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + bHasHeadset = false; + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Check For Headset couldn't get the voice interface!")); + return; + } + + bHasHeadset = VoiceInterface->IsHeadsetPresent(LocalPlayerNum); +} + +void UAdvancedVoiceLibrary::StartNetworkedVoice(uint8 LocalPlayerNum) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Start Networked Voice couldn't get the voice interface!")); + return; + } + + VoiceInterface->StartNetworkedVoice(LocalPlayerNum); +} + +void UAdvancedVoiceLibrary::StopNetworkedVoice(uint8 LocalPlayerNum) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Start Networked Voice couldn't get the voice interface!")); + return; + } + + VoiceInterface->StopNetworkedVoice(LocalPlayerNum); +} + +bool UAdvancedVoiceLibrary::RegisterLocalTalker(uint8 LocalPlayerNum) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Register Local Talker couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->RegisterLocalTalker(LocalPlayerNum); +} + +void UAdvancedVoiceLibrary::RegisterAllLocalTalkers() +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Register Local Talkers couldn't get the voice interface!")); + return; + } + + VoiceInterface->RegisterLocalTalkers(); +} + + +void UAdvancedVoiceLibrary::UnRegisterLocalTalker(uint8 LocalPlayerNum) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Unregister Local Talker couldn't get the voice interface!")); + return; + } + + VoiceInterface->UnregisterLocalTalker(LocalPlayerNum); +} + +void UAdvancedVoiceLibrary::UnRegisterAllLocalTalkers() +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("UnRegister All Local Talkers couldn't get the voice interface!")); + return; + } + + VoiceInterface->UnregisterLocalTalkers(); +} + +bool UAdvancedVoiceLibrary::RegisterRemoteTalker(const FBPUniqueNetId& UniqueNetId) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Register Remote Talker couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->RegisterRemoteTalker(*UniqueNetId.GetUniqueNetId()); +} + +bool UAdvancedVoiceLibrary::UnRegisterRemoteTalker(const FBPUniqueNetId& UniqueNetId) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("UnRegister Remote Talker couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->UnregisterRemoteTalker(*UniqueNetId.GetUniqueNetId()); +} + +void UAdvancedVoiceLibrary::RemoveAllRemoteTalkers() +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Remove All Remote Talkers couldn't get the voice interface!")); + return; + } + + VoiceInterface->RemoveAllRemoteTalkers(); +} + +bool UAdvancedVoiceLibrary::IsLocalPlayerTalking(uint8 LocalPlayerNum) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Is Local Player Talking couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->IsLocalPlayerTalking(LocalPlayerNum); +} + +bool UAdvancedVoiceLibrary::IsRemotePlayerTalking(const FBPUniqueNetId& UniqueNetId) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Is Remote Player Talking couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->IsRemotePlayerTalking(*UniqueNetId.GetUniqueNetId()); +} + +bool UAdvancedVoiceLibrary::IsPlayerMuted(uint8 LocalUserNumChecking, const FBPUniqueNetId& UniqueNetId) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Is Player Muted couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->IsMuted(LocalUserNumChecking, *UniqueNetId.GetUniqueNetId()); +} + +bool UAdvancedVoiceLibrary::MuteRemoteTalker(uint8 LocalUserNum, const FBPUniqueNetId& UniqueNetId, bool bIsSystemWide) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Mute Remote Talker couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->MuteRemoteTalker(LocalUserNum, *UniqueNetId.GetUniqueNetId(), bIsSystemWide); +} + +bool UAdvancedVoiceLibrary::UnMuteRemoteTalker(uint8 LocalUserNum, const FBPUniqueNetId& UniqueNetId, bool bIsSystemWide) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Unmute Remote Talker couldn't get the voice interface!")); + return false; + } + + return VoiceInterface->UnmuteRemoteTalker(LocalUserNum, *UniqueNetId.GetUniqueNetId(), bIsSystemWide); +} + + +void UAdvancedVoiceLibrary::GetNumLocalTalkers(int32 & NumLocalTalkers) +{ + IOnlineVoicePtr VoiceInterface = Online::GetVoiceInterface(); + + if (!VoiceInterface.IsValid()) + { + NumLocalTalkers = 0; + UE_LOG(AdvancedVoiceLog, Warning, TEXT("Unmute Remote Talker couldn't get the voice interface!")); + return; + } + + NumLocalTalkers = VoiceInterface->GetNumLocalTalkers(); +} \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/BlueprintDataDefinitions.h b/Source/AdvancedSessions/Private/BlueprintDataDefinitions.h new file mode 100644 index 0000000..c5beb8b --- /dev/null +++ b/Source/AdvancedSessions/Private/BlueprintDataDefinitions.h @@ -0,0 +1,328 @@ +#pragma once + +#include "Engine.h" +#include "Core.h" +#include "OnlineSessionInterface.h" +#include "OnlineSessionSettings.h" +#include "OnlineDelegateMacros.h" +#include "OnlineSubsystem.h" +#include "OnlineSubsystemImpl.h" +#include "OnlineSubsystemUtils.h" +#include "OnlineSubsystemUtilsModule.h" +#include "ModuleManager.h" +#include "OnlineSubsystemUtilsClasses.h" +#include "BlueprintDataDefinitions.generated.h" + + +UENUM() +namespace ESessionSettingSearchResult +{ + enum Type + { + // Found the setting + Found, + + // Did not find the setting + NotFound, + + // Was not the correct ype + WrongType + }; +} + +// This makes a lot of the blueprint functions cleaner +UENUM() +namespace EBlueprintResultSwitch +{ + enum Type + { + // On Success + OnSuccess, + + // On Failure + OnFailure + }; +} + + +// Wanted this to be switchable in the editor +UENUM(BlueprintType) +namespace EBPOnlinePresenceState +{ + enum Type + { + Online, + Offline, + Away, + ExtendedAway, + DoNotDisturb, + Chat + }; +} + +UENUM(BlueprintType) +namespace EBPOnlineSessionState +{ + enum Type + { + /** An online session has not been created yet */ + NoSession, + /** An online session is in the process of being created */ + Creating, + /** Session has been created but the session hasn't started (pre match lobby) */ + Pending, + /** Session has been asked to start (may take time due to communication with backend) */ + Starting, + /** The current session has started. Sessions with join in progress disabled are no longer joinable */ + InProgress, + /** The session is still valid, but the session is no longer being played (post match lobby) */ + Ending, + /** The session is closed and any stats committed */ + Ended, + /** The session is being destroyed */ + Destroying + }; +} + +// Boy oh boy is this a dirty hack, but I can't figure out a good way to do it otherwise at the moment +// The UniqueNetId is an abstract class so I can't exactly re-initialize it to make a shared pointer on some functions +// So I made the blueprintable UniqueNetID into a dual variable struct with access functions and I am converting the const var for the pointer +// I really need to re-think this later +USTRUCT(BlueprintType) +struct FBPUniqueNetId +{ + GENERATED_USTRUCT_BODY() + +private: + bool bUseDirectPointer; + + +public: + TSharedPtr UniqueNetId; + const FUniqueNetId * UniqueNetIdPtr; + + void SetUniqueNetId(const TSharedPtr &ID) + { + bUseDirectPointer = false; + UniqueNetIdPtr = nullptr; + UniqueNetId = ID; + } + + void SetUniqueNetId(const FUniqueNetId *ID) + { + bUseDirectPointer = true; + UniqueNetIdPtr = ID; + } + + bool IsValid() const + { + if (bUseDirectPointer && UniqueNetIdPtr != nullptr) + { + return true; + } + else if (UniqueNetId.IsValid()) + { + return true; + } + else + return false; + + } + + const FUniqueNetId* GetUniqueNetId() const + { + if (bUseDirectPointer && UniqueNetIdPtr != nullptr) + { + // No longer converting to non const as all functions now pass const UniqueNetIds + return /*const_cast*/(UniqueNetIdPtr); + } + else if (UniqueNetId.IsValid()) + { + return UniqueNetId.Get(); + } + else + return nullptr; + } + + FBPUniqueNetId() + { + bUseDirectPointer = false; + UniqueNetIdPtr = nullptr; + } +}; + +USTRUCT(BluePrintType) +struct FBPOnlineUser +{ + GENERATED_USTRUCT_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FBPUniqueNetId UniqueNetId; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FString DisplayName; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FString RealName; +}; + +USTRUCT(BluePrintType) +struct FBPOnlineRecentPlayer : public FBPOnlineUser +{ + GENERATED_USTRUCT_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FString LastSeen; +}; + +USTRUCT(BlueprintType) +struct FBPFriendInfo +{ + GENERATED_USTRUCT_BODY() + +public: + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FString DisplayName; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FString RealName; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + TEnumAsByte OnlineState; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + FBPUniqueNetId UniqueNetId; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Online|Friend") + bool bIsPlayingSameGame; +}; + +/** The types of comparison operations for a given search query */ +// Used to compare session properties +UENUM(BlueprintType) +namespace EOnlineComparisonOpRedux +{ + enum Type + { + Equals, + NotEquals, + GreaterThan, + GreaterThanEquals, + LessThan, + LessThanEquals, + }; +} + + +// Used to store session properties before converting to FVariantData +USTRUCT(BlueprintType) +struct FSessionPropertyKeyPair +{ + GENERATED_USTRUCT_BODY() + + FName Key; + FVariantData Data; +}; + + +// Sent to the FindSessionsAdvanced to filter the end results +USTRUCT(BlueprintType) +struct FSessionsSearchSetting +{ + GENERATED_USTRUCT_BODY() + //UPROPERTY() + + + // Had to make a copy of this to account for the original not being exposed to blueprints + /** How is this session setting compared on the backend searches */ + TEnumAsByte ComparisonOp; + + // The key pair to search for + FSessionPropertyKeyPair PropertyKeyPair; +}; + +// Couldn't use the default one as it is not exposed to other modules, had to re-create it here +// Helper class for various methods to reduce the call hierarchy +struct FOnlineSubsystemBPCallHelperAdvanced +{ +public: + FOnlineSubsystemBPCallHelperAdvanced(const TCHAR* CallFunctionContext, UWorld* World, FName SystemName = NAME_None) + : OnlineSub(Online::GetSubsystem(World, SystemName)) + , FunctionContext(CallFunctionContext) + { + if (OnlineSub == nullptr) + { + FFrame::KismetExecutionMessage(*FString::Printf(TEXT("%s - Invalid or uninitialized OnlineSubsystem"), FunctionContext), ELogVerbosity::Warning); + } + } + + void QueryIDFromPlayerController(APlayerController* PlayerController) + { + UserID.Reset(); + //return const_cast(UniqueNetIdPtr); + if (APlayerState* PlayerState = (PlayerController != NULL) ? PlayerController->PlayerState : NULL) + { + UserID = PlayerState->UniqueId.GetUniqueNetId(); + if (!UserID.IsValid()) + { + FFrame::KismetExecutionMessage(*FString::Printf(TEXT("%s - Cannot map local player to unique net ID"), FunctionContext), ELogVerbosity::Warning); + } + } + else + { + FFrame::KismetExecutionMessage(*FString::Printf(TEXT("%s - Invalid player state"), FunctionContext), ELogVerbosity::Warning); + } + } + + + bool IsValid() const + { + return UserID.IsValid() && (OnlineSub != nullptr); + } + +public: + //TSharedPtr& GetUniqueNetId() + TSharedPtr UserID; + IOnlineSubsystem* const OnlineSub; + const TCHAR* FunctionContext; +}; +class FOnlineSearchSettingsEx : public FOnlineSearchSettings +{ + /** + * Sets a key value pair combination that defines a search parameter + * + * @param Key key for the setting + * @param Value value of the setting + * @param InType type of comparison + */ +public: + + void HardSet(FName Key, const FVariantData& Value, EOnlineComparisonOpRedux::Type CompOp) + { + FOnlineSessionSearchParam* SearchParam = SearchParams.Find(Key); + + EOnlineComparisonOp::Type op; + + switch (CompOp) + { + case EOnlineComparisonOpRedux::Equals: op = EOnlineComparisonOp::Equals; break; + case EOnlineComparisonOpRedux::GreaterThan: op = EOnlineComparisonOp::GreaterThan; break; + case EOnlineComparisonOpRedux::GreaterThanEquals: op = EOnlineComparisonOp::GreaterThanEquals; break; + case EOnlineComparisonOpRedux::LessThan: op = EOnlineComparisonOp::LessThan; break; + case EOnlineComparisonOpRedux::LessThanEquals: op = EOnlineComparisonOp::LessThanEquals; break; + case EOnlineComparisonOpRedux::NotEquals: op = EOnlineComparisonOp::NotEquals; break; + default: op = EOnlineComparisonOp::Equals; break; + } + + if (SearchParam) + { + SearchParam->Data = Value; + SearchParam->ComparisonOp = op; + } + else + { + FOnlineSessionSearchParam searchSetting((int)0, op); + searchSetting.Data = Value; + SearchParams.Add(Key, searchSetting); + } + } +}; + +#define INVALID_INDEX -1 \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/CancelFindSessionsCallbackProxy.cpp b/Source/AdvancedSessions/Private/CancelFindSessionsCallbackProxy.cpp new file mode 100644 index 0000000..4d6d86d --- /dev/null +++ b/Source/AdvancedSessions/Private/CancelFindSessionsCallbackProxy.cpp @@ -0,0 +1,71 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubSystemHeader.h" +#include "CancelFindSessionsCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UCancelFindSessionsCallbackProxy + +UCancelFindSessionsCallbackProxy::UCancelFindSessionsCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , Delegate(FOnCancelFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted)) +{ +} + +UCancelFindSessionsCallbackProxy* UCancelFindSessionsCallbackProxy::CancelFindSessions(UObject* WorldContextObject, class APlayerController* PlayerController) +{ + UCancelFindSessionsCallbackProxy* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void UCancelFindSessionsCallbackProxy::Activate() +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("CancelFindSessions"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + DelegateHandle = Sessions->AddOnCancelFindSessionsCompleteDelegate_Handle(Delegate); + Sessions->CancelFindSessions(); + + // OnCompleted will get called, nothing more to do now + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + } + + // Fail immediately + OnFailure.Broadcast(); +} + +void UCancelFindSessionsCallbackProxy::OnCompleted(bool bWasSuccessful) +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("CancelFindSessionsCallback"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + Sessions->ClearOnCancelFindSessionsCompleteDelegate_Handle(DelegateHandle); + } + } + + if (bWasSuccessful) + { + OnSuccess.Broadcast(); + } + else + { + OnFailure.Broadcast(); + } +} diff --git a/Source/AdvancedSessions/Private/CreateSessionCallbackProxyAdvanced.cpp b/Source/AdvancedSessions/Private/CreateSessionCallbackProxyAdvanced.cpp new file mode 100644 index 0000000..f6e237c --- /dev/null +++ b/Source/AdvancedSessions/Private/CreateSessionCallbackProxyAdvanced.cpp @@ -0,0 +1,135 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#include "OnlineSubSystemHeader.h" +#include "CreateSessionCallbackProxyAdvanced.h" + +////////////////////////////////////////////////////////////////////////// +// UCreateSessionCallbackProxyAdvanced + +UCreateSessionCallbackProxyAdvanced::UCreateSessionCallbackProxyAdvanced(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , CreateCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateCompleted)) + , StartCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnStartCompleted)) + , NumPublicConnections(1) +{ +} + +UCreateSessionCallbackProxyAdvanced* UCreateSessionCallbackProxyAdvanced::CreateAdvancedSession(UObject* WorldContextObject, const TArray &ExtraSettings, class APlayerController* PlayerController, int32 PublicConnections, bool bUseLAN, bool bAllowInvites, bool bIsDedicatedServer) +{ + UCreateSessionCallbackProxyAdvanced* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->NumPublicConnections = PublicConnections; + Proxy->bUseLAN = bUseLAN; + Proxy->WorldContextObject = WorldContextObject; + Proxy->bAllowInvites = bAllowInvites; + Proxy->ExtraSettings = ExtraSettings; + Proxy->bDedicatedServer = bIsDedicatedServer; + + return Proxy; +} + +void UCreateSessionCallbackProxyAdvanced::Activate() +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("CreateSession"), GEngine->GetWorldFromContextObject(WorldContextObject)); + + if (PlayerControllerWeakPtr.IsValid() ) + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.OnlineSub != nullptr) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + CreateCompleteDelegateHandle = Sessions->AddOnCreateSessionCompleteDelegate_Handle(CreateCompleteDelegate); + + FOnlineSessionSettings Settings; + Settings.NumPublicConnections = NumPublicConnections; + Settings.bShouldAdvertise = true; + Settings.bAllowJoinInProgress = true; + Settings.bIsLANMatch = bUseLAN; + Settings.bUsesPresence = true; + Settings.bAllowJoinViaPresence = true; + Settings.bIsDedicated = bDedicatedServer; + + // These are about the only changes over the standard Create Sessions Node + Settings.bAllowInvites = bAllowInvites; + + FOnlineSessionSetting ExtraSetting; + for (int i = 0; i < ExtraSettings.Num(); i++) + { + ExtraSetting.Data = ExtraSettings[i].Data; + // ViaOnlineServiceAndPing + ExtraSetting.AdvertisementType = EOnlineDataAdvertisementType::ViaOnlineService; + Settings.Settings.Add(ExtraSettings[i].Key, ExtraSetting); + } + + + if (PlayerControllerWeakPtr.IsValid() && Helper.UserID.IsValid()) + Sessions->CreateSession(*Helper.UserID, GameSessionName, Settings); + else + Sessions->CreateSession(NULL, GameSessionName, Settings); + + // OnCreateCompleted will get called, nothing more to do now + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + } + + // Fail immediately + OnFailure.Broadcast(); +} + +void UCreateSessionCallbackProxyAdvanced::OnCreateCompleted(FName SessionName, bool bWasSuccessful) +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("CreateSessionCallback"), GEngine->GetWorldFromContextObject(WorldContextObject)); + //Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.OnlineSub != nullptr) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + Sessions->ClearOnCreateSessionCompleteDelegate_Handle(CreateCompleteDelegateHandle); + + if (bWasSuccessful) + { + StartCompleteDelegateHandle = Sessions->AddOnStartSessionCompleteDelegate_Handle(StartCompleteDelegate); + Sessions->StartSession(GameSessionName); + + // OnStartCompleted will get called, nothing more to do now + return; + } + } + } + + if (!bWasSuccessful) + { + OnFailure.Broadcast(); + } +} + +void UCreateSessionCallbackProxyAdvanced::OnStartCompleted(FName SessionName, bool bWasSuccessful) +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("StartSessionCallback"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.OnlineSub != nullptr) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + Sessions->ClearOnStartSessionCompleteDelegate_Handle(StartCompleteDelegateHandle); + } + } + + if (bWasSuccessful) + { + OnSuccess.Broadcast(); + } + else + { + OnFailure.Broadcast(); + } +} diff --git a/Source/AdvancedSessions/Private/EndSessionCallbackProxy.cpp b/Source/AdvancedSessions/Private/EndSessionCallbackProxy.cpp new file mode 100644 index 0000000..73caee6 --- /dev/null +++ b/Source/AdvancedSessions/Private/EndSessionCallbackProxy.cpp @@ -0,0 +1,79 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubSystemHeader.h" +#include "EndSessionCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UEndSessionCallbackProxy + +UEndSessionCallbackProxy::UEndSessionCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , Delegate(FOnEndSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted)) +{ +} + +UEndSessionCallbackProxy* UEndSessionCallbackProxy::EndSession(UObject* WorldContextObject, class APlayerController* PlayerController) +{ + UEndSessionCallbackProxy* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void UEndSessionCallbackProxy::Activate() +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("EndSession"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + FNamedOnlineSession* Session = Sessions->GetNamedSession(GameSessionName); + if (Session && + Session->SessionState == EOnlineSessionState::InProgress) + { + DelegateHandle = Sessions->AddOnEndSessionCompleteDelegate_Handle(Delegate); + Sessions->EndSession(GameSessionName); + } + else + { + OnSuccess.Broadcast(); + } + // OnCompleted will get called, nothing more to do now + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + } + + // Fail immediately + OnFailure.Broadcast(); +} + +void UEndSessionCallbackProxy::OnCompleted(FName SessionName, bool bWasSuccessful) +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("EndSessionCallback"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + Sessions->ClearOnEndSessionCompleteDelegate_Handle(DelegateHandle); + } + } + + if (bWasSuccessful) + { + OnSuccess.Broadcast(); + } + else + { + OnFailure.Broadcast(); + } +} diff --git a/Source/AdvancedSessions/Private/FindFriendSessionCallbackProxy.cpp b/Source/AdvancedSessions/Private/FindFriendSessionCallbackProxy.cpp new file mode 100644 index 0000000..89524a5 --- /dev/null +++ b/Source/AdvancedSessions/Private/FindFriendSessionCallbackProxy.cpp @@ -0,0 +1,88 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#include "OnlineSubSystemHeader.h" +#include "FindFriendSessionCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UGetRecentPlayersCallbackProxy +DEFINE_LOG_CATEGORY(AdvancedFindFriendSessionLog); + +UFindFriendSessionCallbackProxy::UFindFriendSessionCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , OnFindFriendSessionCompleteDelegate(FOnFindFriendSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnFindFriendSessionCompleted)) +{ +} + +UFindFriendSessionCallbackProxy* UFindFriendSessionCallbackProxy::FindFriendSession(UObject* WorldContextObject, APlayerController *PlayerController, const FBPUniqueNetId &FriendUniqueNetId) +{ + UFindFriendSessionCallbackProxy* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->cUniqueNetId = FriendUniqueNetId; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void UFindFriendSessionCallbackProxy::Activate() +{ + if (!cUniqueNetId.IsValid()) + { + // Fail immediately + UE_LOG(AdvancedFindFriendSessionLog, Warning, TEXT("FindFriendSession Failed received a bad UniqueNetId!")); + FBlueprintSessionResult EmptyResult; + OnFailure.Broadcast(EmptyResult); + return; + } + + if (!PlayerControllerWeakPtr.IsValid()) + { + // Fail immediately + UE_LOG(AdvancedFindFriendSessionLog, Warning, TEXT("FindFriendSession Failed received a bad playercontroller!")); + FBlueprintSessionResult EmptyResult; + OnFailure.Broadcast(EmptyResult); + return; + } + + IOnlineSessionPtr Sessions = Online::GetSessionInterface(); + + if (Sessions.IsValid()) + { + ULocalPlayer* Player = Cast(PlayerControllerWeakPtr->Player); + + if (!Player) + { + // Fail immediately + UE_LOG(AdvancedFindFriendSessionLog, Warning, TEXT("FindFriendSession Failed couldn't cast to ULocalPlayer!")); + FBlueprintSessionResult EmptyResult; + OnFailure.Broadcast(EmptyResult); + return; + } + + FindFriendSessionCompleteDelegateHandle = Sessions->AddOnFindFriendSessionCompleteDelegate_Handle(Player->GetControllerId(), OnFindFriendSessionCompleteDelegate); + + Sessions->FindFriendSession(Player->GetControllerId(),*cUniqueNetId.GetUniqueNetId()); + return; + } + // Fail immediately + FBlueprintSessionResult EmptyResult; + OnFailure.Broadcast(EmptyResult); +} + +void UFindFriendSessionCallbackProxy::OnFindFriendSessionCompleted(int32 LocalPlayer, bool bWasSuccessful, const FOnlineSessionSearchResult& SessionInfo) +{ + IOnlineSessionPtr Sessions = Online::GetSessionInterface(); + + if (Sessions.IsValid()) + Sessions->ClearOnFindFriendSessionCompleteDelegate_Handle(LocalPlayer, FindFriendSessionCompleteDelegateHandle); + + if ( bWasSuccessful ) + { + FBlueprintSessionResult Result; + Result.OnlineResult = SessionInfo; + OnSuccess.Broadcast(Result); + } + else + { + UE_LOG(AdvancedFindFriendSessionLog, Warning, TEXT("FindFriendSession Failed")); + FBlueprintSessionResult EmptyResult; + OnFailure.Broadcast(EmptyResult); + } +} diff --git a/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp b/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp new file mode 100644 index 0000000..aa1c61c --- /dev/null +++ b/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp @@ -0,0 +1,317 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubSystemHeader.h" +#include "FindSessionsCallbackProxyAdvanced.h" + +////////////////////////////////////////////////////////////////////////// +// UFindSessionsCallbackProxyAdvanced + + +UFindSessionsCallbackProxyAdvanced::UFindSessionsCallbackProxyAdvanced(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , Delegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted)) + , bUseLAN(false) +{ +} + +UFindSessionsCallbackProxyAdvanced* UFindSessionsCallbackProxyAdvanced::FindSessionsAdvanced(UObject* WorldContextObject, class APlayerController* PlayerController, int MaxResults, bool bUseLAN, const TArray &Filters) +{ + UFindSessionsCallbackProxyAdvanced* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->bUseLAN = bUseLAN; + Proxy->MaxResults = MaxResults; + Proxy->WorldContextObject = WorldContextObject; + Proxy->SearchSettings = Filters; + return Proxy; +} + +void UFindSessionsCallbackProxyAdvanced::Activate() +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("FindSessions"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + DelegateHandle = Sessions->AddOnFindSessionsCompleteDelegate_Handle(Delegate); + + SearchObject = MakeShareable(new FOnlineSessionSearch); + SearchObject->MaxSearchResults = MaxResults; + SearchObject->bIsLanQuery = bUseLAN; + //SearchObject->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); + + // Create temp filter variable, because I had to re-define a blueprint version of this, it is required. + FOnlineSearchSettingsEx tem; + tem.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); + + // Filter results + if (SearchSettings.Num() > 0) + { + for (int i = 0; i < SearchSettings.Num(); i++) + { + // Function that was added to make directly adding a FVariant possible + tem.HardSet(SearchSettings[i].PropertyKeyPair.Key, SearchSettings[i].PropertyKeyPair.Data, SearchSettings[i].ComparisonOp); + } + } + + // Copy the derived temp variable over to it's base class + SearchObject->QuerySettings = tem; + + Sessions->FindSessions(*Helper.UserID, SearchObject.ToSharedRef()); + + // OnQueryCompleted will get called, nothing more to do now + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + } + + // Fail immediately + TArray Results; + OnFailure.Broadcast(Results); +} + +void UFindSessionsCallbackProxyAdvanced::OnCompleted(bool bSuccess) +{ + FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("FindSessionsCallback"), GEngine->GetWorldFromContextObject(WorldContextObject)); + Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); + + if (Helper.IsValid()) + { + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + if (Sessions.IsValid()) + { + Sessions->ClearOnFindSessionsCompleteDelegate_Handle(DelegateHandle); + } + } + + TArray Results; + + if (bSuccess && SearchObject.IsValid()) + { + // Just log the results for now, will need to add a blueprint-compatible search result struct + for (auto& Result : SearchObject->SearchResults) + { + /* bool bAddResult = true; + + // Filter results + if (SearchSettings.Num() > 0) + { + FOnlineSessionSetting * setting; + for (int i = 0; i < SearchSettings.Num(); i++) + { + setting = Result.Session.SessionSettings.Settings.Find(SearchSettings[i].PropertyKeyPair.Key); + + // Couldn't find this key + if (!setting) + continue; + + if (!CompareVariants(setting->Data, SearchSettings[i].PropertyKeyPair.Data, SearchSettings[i].ComparisonOp)) + { + bAddResult = false; + break; + } + } + }*/ + + //if (bAddResult) + //{ + FString ResultText = FString::Printf(TEXT("Found a session. Ping is %d"), Result.PingInMs); + + FFrame::KismetExecutionMessage(*ResultText, ELogVerbosity::Log); + + FBlueprintSessionResult BPResult; + BPResult.OnlineResult = Result; + Results.Add(BPResult); + //} + } + OnSuccess.Broadcast(Results); + } + else + { + OnFailure.Broadcast(Results); + } +} + + +void UFindSessionsCallbackProxyAdvanced::FilterSessionResults(const TArray &SessionResults, const TArray &Filters, TArray &FilteredResults) +{ + for (int j = 0; j < SessionResults.Num(); j++) + { + bool bAddResult = true; + + // Filter results + if (Filters.Num() > 0) + { + const FOnlineSessionSetting * setting; + for (int i = 0; i < Filters.Num(); i++) + { + setting = SessionResults[j].OnlineResult.Session.SessionSettings.Settings.Find(Filters[i].PropertyKeyPair.Key); + + // Couldn't find this key + if (!setting) + continue; + + if (!CompareVariants(setting->Data, Filters[i].PropertyKeyPair.Data, Filters[i].ComparisonOp)) + { + bAddResult = false; + break; + } + } + } + + if (bAddResult) + FilteredResults.Add(SessionResults[j]); + } + + return; +} + + +bool UFindSessionsCallbackProxyAdvanced::CompareVariants(const FVariantData &A, const FVariantData &B, EOnlineComparisonOpRedux::Type Comparator) +{ + if (A.GetType() != B.GetType()) + return false; + + switch (A.GetType()) + { + case EOnlineKeyValuePairDataType::Bool: + { + bool bA, bB; + A.GetValue(bA); + B.GetValue(bB); + switch (Comparator) + { + case EOnlineComparisonOpRedux::Equals: + return bA == bB; break; + case EOnlineComparisonOpRedux::NotEquals: + return bA != bB; break; + default: + return false;break; + } + } + case EOnlineKeyValuePairDataType::Double: + { + double bA, bB; + A.GetValue(bA); + B.GetValue(bB); + switch (Comparator) + { + case EOnlineComparisonOpRedux::Equals: + return bA == bB; break; + case EOnlineComparisonOpRedux::NotEquals: + return bA != bB; break; + case EOnlineComparisonOpRedux::GreaterThanEquals: + return (bA == bB || bA > bB); break; + case EOnlineComparisonOpRedux::LessThanEquals: + return (bA == bB || bA < bB); break; + case EOnlineComparisonOpRedux::GreaterThan: + return bA > bB; break; + case EOnlineComparisonOpRedux::LessThan: + return bA < bB; break; + default: + return false; break; + } + } + case EOnlineKeyValuePairDataType::Float: + { + float tbA, tbB; + double bA, bB; + A.GetValue(tbA); + B.GetValue(tbB); + bA = (double)tbA; + bB = (double)tbB; + switch (Comparator) + { + case EOnlineComparisonOpRedux::Equals: + return bA == bB; break; + case EOnlineComparisonOpRedux::NotEquals: + return bA != bB; break; + case EOnlineComparisonOpRedux::GreaterThanEquals: + return (bA == bB || bA > bB); break; + case EOnlineComparisonOpRedux::LessThanEquals: + return (bA == bB || bA < bB); break; + case EOnlineComparisonOpRedux::GreaterThan: + return bA > bB; break; + case EOnlineComparisonOpRedux::LessThan: + return bA < bB; break; + default: + return false; break; + } + } + case EOnlineKeyValuePairDataType::Int32: + { + int32 bA, bB; + A.GetValue(bA); + B.GetValue(bB); + switch (Comparator) + { + case EOnlineComparisonOpRedux::Equals: + return bA == bB; break; + case EOnlineComparisonOpRedux::NotEquals: + return bA != bB; break; + case EOnlineComparisonOpRedux::GreaterThanEquals: + return (bA == bB || bA > bB); break; + case EOnlineComparisonOpRedux::LessThanEquals: + return (bA == bB || bA < bB); break; + case EOnlineComparisonOpRedux::GreaterThan: + return bA > bB; break; + case EOnlineComparisonOpRedux::LessThan: + return bA < bB; break; + default: + return false; break; + } + } + case EOnlineKeyValuePairDataType::Int64: + { + uint64 bA, bB; + A.GetValue(bA); + B.GetValue(bB); + switch (Comparator) + { + case EOnlineComparisonOpRedux::Equals: + return bA == bB; break; + case EOnlineComparisonOpRedux::NotEquals: + return bA != bB; break; + case EOnlineComparisonOpRedux::GreaterThanEquals: + return (bA == bB || bA > bB); break; + case EOnlineComparisonOpRedux::LessThanEquals: + return (bA == bB || bA < bB); break; + case EOnlineComparisonOpRedux::GreaterThan: + return bA > bB; break; + case EOnlineComparisonOpRedux::LessThan: + return bA < bB; break; + default: + return false; break; + } + } + + case EOnlineKeyValuePairDataType::String: + { + FString bA, bB; + A.GetValue(bA); + B.GetValue(bB); + switch (Comparator) + { + case EOnlineComparisonOpRedux::Equals: + return bA == bB; break; + case EOnlineComparisonOpRedux::NotEquals: + return bA != bB; break; + default: + return false; break; + } + } + + case EOnlineKeyValuePairDataType::Empty: + case EOnlineKeyValuePairDataType::Blob: + default: + return false; break; + } + + + +} \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/GetFriendsCallbackProxy.cpp b/Source/AdvancedSessions/Private/GetFriendsCallbackProxy.cpp new file mode 100644 index 0000000..b43fb69 --- /dev/null +++ b/Source/AdvancedSessions/Private/GetFriendsCallbackProxy.cpp @@ -0,0 +1,81 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#include "OnlineSubSystemHeader.h" +#include "GetFriendsCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UGetFriendsCallbackProxy +DEFINE_LOG_CATEGORY(AdvancedGetFriendsLog); + +UGetFriendsCallbackProxy::UGetFriendsCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , FriendListReadCompleteDelegate(FOnReadFriendsListComplete::CreateUObject(this, &ThisClass::OnReadFriendsListCompleted)) +{ +} + +UGetFriendsCallbackProxy* UGetFriendsCallbackProxy::GetAndStoreFriendsList(UObject* WorldContextObject, class APlayerController* PlayerController) +{ + UGetFriendsCallbackProxy* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void UGetFriendsCallbackProxy::Activate() +{ + if (!PlayerControllerWeakPtr.IsValid()) + { + // Fail immediately + UE_LOG(AdvancedGetFriendsLog, Warning, TEXT("GetFriends Failed received a bad player controller!")); + TArray EmptyArray; + OnFailure.Broadcast(EmptyArray); + return; + } + + IOnlineFriendsPtr Friends = Online::GetFriendsInterface(); + if (Friends.IsValid()) + { + ULocalPlayer* Player = Cast(PlayerControllerWeakPtr->Player); + + Friends->ReadFriendsList(Player->GetControllerId(), EFriendsLists::ToString((EFriendsLists::Type::Default)), FriendListReadCompleteDelegate); + return; + } + + // Fail immediately + TArray EmptyArray; + + OnFailure.Broadcast(EmptyArray); +} + +void UGetFriendsCallbackProxy::OnReadFriendsListCompleted(int32 LocalUserNum, bool bWasSuccessful, const FString& ListName, const FString& ErrorString) +{ + if (bWasSuccessful) + { + IOnlineFriendsPtr Friends = Online::GetFriendsInterface(); + if (Friends.IsValid()) + { + ULocalPlayer* Player = Cast(PlayerControllerWeakPtr->Player); + + TArray FriendsListOut; + TArray< TSharedRef > FriendList; + Friends->GetFriendsList(LocalUserNum, ListName, FriendList); + + for (int32 i = 0; i < FriendList.Num(); i++) + { + TSharedRef Friend = FriendList[i]; + FBPFriendInfo BPF; + BPF.OnlineState = ((EBPOnlinePresenceState::Type)((int32)Friend->GetPresence().Status.State)); + BPF.DisplayName = Friend->GetDisplayName(); + BPF.RealName = Friend->GetRealName(); + BPF.UniqueNetId.SetUniqueNetId(Friend->GetUserId()); + FriendsListOut.Add(BPF); + } + + OnSuccess.Broadcast(FriendsListOut); + } + } + else + { + TArray EmptyArray; + OnFailure.Broadcast(EmptyArray); + } +} diff --git a/Source/AdvancedSessions/Private/GetRecentPlayersCallbackProxy.cpp b/Source/AdvancedSessions/Private/GetRecentPlayersCallbackProxy.cpp new file mode 100644 index 0000000..5df45e3 --- /dev/null +++ b/Source/AdvancedSessions/Private/GetRecentPlayersCallbackProxy.cpp @@ -0,0 +1,85 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#include "OnlineSubSystemHeader.h" +#include "GetRecentPlayersCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UGetRecentPlayersCallbackProxy +DEFINE_LOG_CATEGORY(AdvancedGetRecentPlayersLog); + +UGetRecentPlayersCallbackProxy::UGetRecentPlayersCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , QueryRecentPlayersCompleteDelegate(FOnQueryRecentPlayersCompleteDelegate::CreateUObject(this, &ThisClass::OnQueryRecentPlayersCompleted)) +{ +} + +UGetRecentPlayersCallbackProxy* UGetRecentPlayersCallbackProxy::GetAndStoreRecentPlayersList(UObject* WorldContextObject, const FBPUniqueNetId& UniqueNetId) +{ + UGetRecentPlayersCallbackProxy* Proxy = NewObject(); + Proxy->cUniqueNetId = UniqueNetId; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void UGetRecentPlayersCallbackProxy::Activate() +{ + if (!cUniqueNetId.IsValid()) + { + // Fail immediately + UE_LOG(AdvancedGetRecentPlayersLog, Warning, TEXT("GetRecentPlayers Failed received a bad UniqueNetId!")); + TArray EmptyArray; + OnFailure.Broadcast(EmptyArray); + return; + } + + IOnlineFriendsPtr Friends = Online::GetFriendsInterface(); + if (Friends.IsValid()) + { + DelegateHandle = Friends->AddOnQueryRecentPlayersCompleteDelegate_Handle(QueryRecentPlayersCompleteDelegate); + + // Testing with null namespace + Friends->QueryRecentPlayers(*(cUniqueNetId.GetUniqueNetId()), ""); + return; + } + // Fail immediately + TArray EmptyArray; + OnFailure.Broadcast(EmptyArray); +} + +void UGetRecentPlayersCallbackProxy::OnQueryRecentPlayersCompleted(const FUniqueNetId &UserID, const FString &Namespace, bool bWasSuccessful, const FString& ErrorString) +{ + + IOnlineFriendsPtr Friends = Online::GetFriendsInterface(); + if (Friends.IsValid()) + Friends->ClearOnQueryRecentPlayersCompleteDelegate_Handle(DelegateHandle); + + + if (bWasSuccessful) + { + // WHOOPS + //IOnlineFriendsPtr Friends = Online::GetFriendsInterface(); + if (Friends.IsValid()) + { + TArray PlayersListOut; + TArray< TSharedRef > PlayerList; + + Friends->GetRecentPlayers(*(cUniqueNetId.GetUniqueNetId()), "", PlayerList); + + for (int32 i = 0; i < PlayerList.Num(); i++) + { + TSharedRef Player = PlayerList[i]; + FBPOnlineRecentPlayer BPF; + BPF.DisplayName = Player->GetDisplayName(); + BPF.RealName = Player->GetRealName(); + BPF.UniqueNetId.SetUniqueNetId(Player->GetUserId()); + PlayersListOut.Add(BPF); + } + + OnSuccess.Broadcast(PlayersListOut); + } + } + else + { + TArray EmptyArray; + OnFailure.Broadcast(EmptyArray); + } +} diff --git a/Source/AdvancedSessions/Private/OnlineSubSystemHeader.h b/Source/AdvancedSessions/Private/OnlineSubSystemHeader.h new file mode 100644 index 0000000..a0e48d1 --- /dev/null +++ b/Source/AdvancedSessions/Private/OnlineSubSystemHeader.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Engine.h" +#include "Core.h" +#include "OnlineSessionInterface.h" +#include "OnlineSessionSettings.h" +#include "OnlineDelegateMacros.h" +#include "OnlineSubsystem.h" +#include "OnlineSubsystemImpl.h" +#include "OnlineSubsystemUtils.h" +#include "OnlineSubsystemUtilsModule.h" +#include "ModuleManager.h" +#include "OnlineSubsystemUtilsClasses.h" +#include "BlueprintDataDefinitions.h" \ No newline at end of file diff --git a/Source/AdvancedSessions/Private/SendFriendInviteCallbackProxy.cpp b/Source/AdvancedSessions/Private/SendFriendInviteCallbackProxy.cpp new file mode 100644 index 0000000..0e25bd0 --- /dev/null +++ b/Source/AdvancedSessions/Private/SendFriendInviteCallbackProxy.cpp @@ -0,0 +1,73 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#include "OnlineSubSystemHeader.h" +#include "SendFriendInviteCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UGetRecentPlayersCallbackProxy +DEFINE_LOG_CATEGORY(AdvancedSendFriendInviteLog); + +USendFriendInviteCallbackProxy::USendFriendInviteCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , OnSendInviteCompleteDelegate(FOnSendInviteComplete::CreateUObject(this, &ThisClass::OnSendInviteComplete)) +{ +} + +USendFriendInviteCallbackProxy* USendFriendInviteCallbackProxy::SendFriendInvite(UObject* WorldContextObject, APlayerController *PlayerController, const FBPUniqueNetId &UniqueNetIDInvited) +{ + USendFriendInviteCallbackProxy* Proxy = NewObject(); + Proxy->PlayerControllerWeakPtr = PlayerController; + Proxy->cUniqueNetId = UniqueNetIDInvited; + Proxy->WorldContextObject = WorldContextObject; + return Proxy; +} + +void USendFriendInviteCallbackProxy::Activate() +{ + if (!cUniqueNetId.IsValid()) + { + // Fail immediately + UE_LOG(AdvancedSendFriendInviteLog, Warning, TEXT("SendFriendInvite Failed received a bad UniqueNetId!")); + OnFailure.Broadcast(); + return; + } + + if (!PlayerControllerWeakPtr.IsValid()) + { + // Fail immediately + UE_LOG(AdvancedSendFriendInviteLog, Warning, TEXT("SendFriendInvite Failed received a bad playercontroller!")); + OnFailure.Broadcast(); + return; + } + + IOnlineFriendsPtr Friends = Online::GetFriendsInterface(); + if (Friends.IsValid()) + { + ULocalPlayer* Player = Cast(PlayerControllerWeakPtr->Player); + + if (!Player) + { + // Fail immediately + UE_LOG(AdvancedSendFriendInviteLog, Warning, TEXT("SendFriendInvite Failed couldn't cast to ULocalPlayer!")); + OnFailure.Broadcast(); + return; + } + + Friends->SendInvite(Player->GetControllerId(), *cUniqueNetId.GetUniqueNetId(), EFriendsLists::ToString((EFriendsLists::Type::Default)), OnSendInviteCompleteDelegate); + return; + } + // Fail immediately + OnFailure.Broadcast(); +} + +void USendFriendInviteCallbackProxy::OnSendInviteComplete(int32 LocalPlayerNum, bool bWasSuccessful, const FUniqueNetId &InvitedPlayer, const FString &ListName, const FString &ErrorString) +{ + if ( bWasSuccessful ) + { + OnSuccess.Broadcast(); + } + else + { + UE_LOG(AdvancedSendFriendInviteLog, Warning, TEXT("SendFriendInvite Failed with error: %s"), *ErrorString); + OnFailure.Broadcast(); + } +} diff --git a/Source/AdvancedSessions/Private/UpdateSessionCallbackProxyAdvanced.cpp b/Source/AdvancedSessions/Private/UpdateSessionCallbackProxyAdvanced.cpp new file mode 100644 index 0000000..0232158 --- /dev/null +++ b/Source/AdvancedSessions/Private/UpdateSessionCallbackProxyAdvanced.cpp @@ -0,0 +1,120 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#include "OnlineSubSystemHeader.h" +#include "UpdateSessionCallbackProxyAdvanced.h" + +////////////////////////////////////////////////////////////////////////// +// UUpdateSessionCallbackProxyAdvanced + +UUpdateSessionCallbackProxyAdvanced::UUpdateSessionCallbackProxyAdvanced(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , OnUpdateSessionCompleteDelegate(FOnUpdateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnUpdateCompleted)) + , NumPublicConnections(1) +{ +} + +UUpdateSessionCallbackProxyAdvanced* UUpdateSessionCallbackProxyAdvanced::UpdateSession(UObject* WorldContextObject, int32 PublicConnections, bool bUseLAN, bool bAllowInvites, bool bAllowJoinInProgress, const TArray &ExtraSettings, bool bRefreshOnlineData, bool bIsDedicatedServer) +{ + UUpdateSessionCallbackProxyAdvanced* Proxy = NewObject(); + Proxy->NumPublicConnections = PublicConnections; + Proxy->bUseLAN = bUseLAN; + Proxy->WorldContextObject = WorldContextObject; + Proxy->bAllowInvites = bAllowInvites; + Proxy->ExtraSettings = ExtraSettings; + Proxy->bRefreshOnlineData = bRefreshOnlineData; + Proxy->bAllowJoinInProgress = bAllowJoinInProgress; + Proxy->bDedicatedServer = bIsDedicatedServer; + return Proxy; +} + +void UUpdateSessionCallbackProxyAdvanced::Activate() +{ + + + IOnlineSessionPtr Sessions = Online::GetSessionInterface(); + + if (Sessions.IsValid()) + { + if (Sessions->GetNumSessions() < 1) + { + OnFailure.Broadcast(); + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("NO REGISTERED SESSIONS!")); + return; + } + + // This gets the actual session itself + //FNamedOnlineSession * curSession = Sessions->GetNamedSession(GameSessionName); + FOnlineSessionSettings* Settings = Sessions->GetSessionSettings(GameSessionName); + + if (!Settings) + { + // Fail immediately + OnFailure.Broadcast(); + return; + } + + OnUpdateSessionCompleteDelegateHandle = Sessions->AddOnUpdateSessionCompleteDelegate_Handle(OnUpdateSessionCompleteDelegate); + + // FOnlineSessionSettings Settings; + //Settings->BuildUniqueId = GetBuildUniqueId(); + Settings->NumPublicConnections = NumPublicConnections; + //Settings->bShouldAdvertise = true; + Settings->bAllowJoinInProgress = bAllowJoinInProgress; + Settings->bIsLANMatch = bUseLAN; + //Settings->bUsesPresence = true; + //Settings->bAllowJoinViaPresence = true; + Settings->bAllowInvites = bAllowInvites; + Settings->bAllowJoinInProgress = bAllowJoinInProgress; + Settings->bIsDedicated = bDedicatedServer; + + FOnlineSessionSetting * fSetting = NULL; + FOnlineSessionSetting ExtraSetting; + for (int i = 0; i < ExtraSettings.Num(); i++) + { + fSetting = Settings->Settings.Find(ExtraSettings[i].Key); + + if (fSetting) + { + fSetting->Data = ExtraSettings[i].Data; + } + else + { + ExtraSetting.Data = ExtraSettings[i].Data; + ExtraSetting.AdvertisementType = EOnlineDataAdvertisementType::ViaOnlineService; + Settings->Settings.Add(ExtraSettings[i].Key, ExtraSetting); + } + } + + Sessions->UpdateSession(GameSessionName, *Settings, bRefreshOnlineData); + + // OnUpdateCompleted will get called, nothing more to do now + return; + } + else + { + FFrame::KismetExecutionMessage(TEXT("Sessions not supported by Online Subsystem"), ELogVerbosity::Warning); + } + // Fail immediately + OnFailure.Broadcast(); + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Sessions not supported")); +} + +void UUpdateSessionCallbackProxyAdvanced::OnUpdateCompleted(FName SessionName, bool bWasSuccessful) +{ + IOnlineSessionPtr Sessions = Online::GetSessionInterface(); + if (Sessions.IsValid()) + { + Sessions->ClearOnUpdateSessionCompleteDelegate_Handle(OnUpdateSessionCompleteDelegateHandle); + + if (bWasSuccessful) + { + OnSuccess.Broadcast(); + return; + } + } + + if (!bWasSuccessful) + { + OnFailure.Broadcast(); + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("WAS NOT SUCCESSFUL")); + } +} \ No newline at end of file