1
0
KF2-Dev-Scripts/OnlineSubsystemSteamworks/Classes/KFOnlineLobbySteamworks.uc
2020-12-13 18:01:13 +03:00

711 lines
20 KiB
Ucode

//=============================================================================
// KFOnlineLobbySteamworks
//=============================================================================
// Steam Lobby functionality for Killing Floor 2
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// - Joshua Rowan 9/25/2013
//=============================================================================
class KFOnlineLobbySteamworks extends OnlineLobbyInterfaceSteamworks within OnlineSubsystemSteamworks
config(Engine)
native;
`if(`STEAM_MATCHMAKING_LOBBY)
/** Steam's Id for this lobby */
var UniqueNetId CurrentLobbyId;
/** Empty Id to test for comparision with initialized ids */
var const UniqueNetId ZeroUniqueId;
/** TRUE after MakeLobby and before OnCreateLobbyComplete */
var bool bCreatingLobby;
/** If set, delay ShowLobbyInviteInterface until OnCreateLobbyComplete */
var bool bWaitingForLobby;
/** TRUE after LobbyJoinGame and before LobbyJoinGameDelegate */
var bool bWaitingForServer;
/** Holds server IP address while waiting for authentication to finish */
var string PendingServerIP;
/** TRUE if logging is enabled */
var bool bDebug;
/** Current lobby visibility */
var ELobbyVisibility LobbyVisibility;
var UniqueNetId InviteLobbyId;
cpptext
{
UBOOL GetServerAddr(DWORD& ip, INT& port);
}
function UniqueNetId GetCurrentLobbyId()
{
return CurrentLobbyId;
}
/*********************************************************************************************
* @name Creating a Lobby
********************************************************************************************* */
/** Returns true if this client is connected to a steam lobby */
function bool IsInLobby()
{
if (CurrentLobbyId != ZeroUniqueId)
{
return true;
}
return false;
}
function bool IsLobbyOwner()
{
local bool success;
local UniqueNetId OwnerID;
if (!IsInLobby())
{
`log(GetFuncName()@"Not in lobby", bDebug, 'DevLobby');
return false;
}
success = GetLobbyAdmin(CurrentLobbyId, OwnerID);
`log(GetFuncName()@"success="$success@"CurrentLobbyId="$UniqueNetIdToString(CurrentLobbyId)@"OwnerID="$UniqueNetIdToString(OwnerID), bDebug, 'DevLobby');
return success && (OwnerID == LoggedInPlayerId);
}
function Initialize()
{
//MakeLobby(6, LV_Friends);
AddLobbyInviteDelegate(OnLobbyInvite);
AddLobbyJoinGameDelegate(OnLobbyJoinGame);
AddLobbyReceiveMessageDelegate(OnLobbyReceiveMessage);
}
/**
* Does some setup and calls the superclass implementation
*
* @param MaxPlayers The maximum number of lobby members
* @param Type The type of lobby to setup (public/private/etc.)
* @param InitialSettings The list of settings to apply to the lobby upon creation
* @return Returns True if a lobby was created, False otherwise
*/
function bool MakeLobby(int MaxPlayers, ELobbyVisibility Type)
{
`log(GetFuncName()@"MaxPlayers="$MaxPlayers@"Type="$Type@"CurrentLobbyId="$UniqueNetIdToString(CurrentLobbyId), bDebug, 'DevLobby');
if ( IsInLobby() )
{
// If we already have a lobby, use this to modify settings
SetLobbyType(CurrentLobbyId, Type);
return false;
}
AddCreateLobbyCompleteDelegate(OnCreateLobbyComplete);
bCreatingLobby = true;
return CreateLobby(MaxPlayers, Type);
}
/**
* Called when 'CreateLobby' completes, returning success/failure, and (if successful) the new lobby UID
*
* @param bWasSuccessful whether or not 'CreateLobby' was successful
* @param LobbyId If successful, the UID of the new lobby
* @param Error If lobby creation failed, returns the error type
*/
function OnCreateLobbyComplete(bool bWasSuccessful, UniqueNetId LobbyId, string Error)
{
local string ConnectedServerIP;
`log(GetFuncName()@"bWasSuccessful="$bWasSuccessful@"Id="$UniqueNetIdToString(LobbyId)@"Error="$Error, bDebug, 'DevLobby');
ClearCreateLobbyCompleteDelegate(OnCreateLobbyComplete);
bCreatingLobby = false;
if (bWasSuccessful)
{
AddLobbyMemberStatusUpdateDelegate(OnLobbyMemberStatusUpdate);
CurrentLobbyId = LobbyId;
ConnectedServerIP = GetConnectedServerIP();
if (ConnectedServerIP != "")
{
`log(GetFuncName()@"SetLobbyServer CurrentLobbyId="$UniqueNetIdToString(CurrentLobbyId)@"ConnectedServerIP="$ConnectedServerIP, bDebug, 'DevLobby');
SetLobbyServer(CurrentLobbyId, ZeroUniqueId, ConnectedServerIP);
}
if (bWaitingForLobby)
{
bWaitingForLobby = false;
ShowLobbyInviteInterfaceInternal();
}
NotifyLobbyStatusChanged(true);
}
}
/*********************************************************************************************
* @name Lobby Invites
********************************************************************************************* */
native function bool ShowLobbyInviteInterfaceInternal();
function ShowLobbyInviteInterface(string InviteMessage)
{
`log(GetFuncName()@"bCreatingLobby="$bCreatingLobby, bDebug, 'DevLobby');
if (bCreatingLobby)
{
bWaitingForLobby = true;
}
else
{
ShowLobbyInviteInterfaceInternal();
}
}
event bool InviteFriendToLobby(string Nickname)
{
local bool Success;
local UniqueNetId FriendId;
`log(GetFuncName()@"Nickname="$Nickname, bDebug, 'DevLobby');
if ( !IsInLobby() )
{
return false;
}
FriendId = GetFriendUniqueId(Nickname);
if (FriendId != ZeroUniqueId)
{
Success = InviteToLobby(CurrentLobbyId, FriendId);
}
if (Success)
{
`log("Friend" @ Nickname @ "with id" @ UniqueNetIdToString(FriendId) @ "invited to party" @ UniqueNetIdToString(CurrentLobbyId), bDebug, 'DevLobby');
}
else
{
`log("Failed to invite Friend" @ nickname @ "to party" @ UniqueNetIdToString(CurrentLobbyId), bDebug, 'DevLobby');
}
return Success;
}
event bool InviteFriendToLobbyByUid(QWORD Uid)
{
local bool Success;
local UniqueNetId FriendId;
if ( !IsInLobby() )
{
return false;
}
FriendId.Uid = Uid;
if (FriendId != ZeroUniqueId)
{
Success = InviteToLobby(CurrentLobbyId, FriendId);
}
if (Success)
{
`log("Friend with id" @ UniqueNetIdToString(FriendId) @ "invited to party" @ UniqueNetIdToString(CurrentLobbyId), bDebug, 'DevLobby');
}
else
{
`log("Failed to invite Friend to party" @ UniqueNetIdToString(CurrentLobbyId), bDebug, 'DevLobby');
}
return Success;
}
/** Finds a UniqueId from a Nickname */
function UniqueNetId GetFriendUniqueId(string Nickname, optional bool IncludeSelf = true)
{
local EOnlineEnumerationReadState readstate;
local array<OnlineFriend> Friends;
local OnlineFriend i;
if (IncludeSelf && Nickname == LoggedInPlayerName)
{
return LoggedInPlayerId;
}
readstate = GetFriendsList(0, Friends);
if (readstate != OERS_Done)
{
`log("Do not have friends list loaded.", bDebug, 'DevLobby');
return ZeroUniqueId;
}
foreach Friends(i)
{
if (Caps(i.NickName) == Caps(Nickname))
{
return i.UniqueId;
}
}
`log("A user with nickname" @ Nickname @ "is not a friend.", bDebug, 'DevLobby');
return ZeroUniqueId;
}
/** Callback on lobby member join, quit, etc... */
function OnLobbyMemberStatusUpdate(const out array<ActiveLobbyInfo> LobbyList, int LobbyIndex, int MemberIndex, int InstigatorIndex,
string Status)
{
local UniqueNetId MemberId;
local string Nickname;
`log(GetFuncName()@"LobbyIndex="$LobbyIndex@"MemberIndex="$MemberIndex@"Status="$Status, bDebug, 'DevLobby');
MemberId = LobbyList[LobbyIndex].Members[MemberIndex].PlayerUID;
if (MemberId != ZeroUniqueId)
{
Nickname = UniqueNetIdToPlayerName(MemberId);
if (Nickname == "")
{
Nickname = "Unknown Nickname";
}
`log(Nickname @ "(UID" @ UniqueNetIdToString(MemberId) $ ") status changed in party" @ UniqueNetIdToString(LobbyList[LobbyIndex].LobbyUID) $ ":" @ Status, bDebug, 'DevLobby');
}
}
function LobbyInvite(UniqueNetId LobbyId, UniqueNetId FriendId, bool bAccepted)
{
OnLobbyInvite(LobbyId, FriendId, bAccepted);
}
/** Client accepted/cancelled an invite from a lobby owner */
function OnLobbyInvite(UniqueNetId LobbyId, UniqueNetId FriendId, bool bAccepted)
{
`log(GetFuncName()@"LobbyId="$UniqueNetIdToString(LobbyId)@"FriendId="$UniqueNetIdToString(FriendId)@"bAccepted="$bAccepted, bDebug, 'DevLobby');
if (!bAccepted)
{
if (LobbyId != CurrentLobbyId)
{
InviteLobbyId = LobbyId;
if(GetPC() != none)
{
GetPC().showInvitePopup(GetFriendNickName(FriendId, false), LobbyId, FriendId);
}
}
return; //for now don't do anything upon receiving the invite
}
if (LobbyId == CurrentLobbyId)
{
`log(GetFuncName()@"Ignoring invitation to current lobby.", bDebug, 'DevLobby');
return;
}
if( GetPC() != none )
{
`log(GetFuncName()@"Accepting lobby invite; disconnecting from current server.", bDebug, 'DevLobby');
GetPC().ConsoleCommand( "disconnect" );
}
AddJoinLobbyCompleteDelegate(OnJoinLobbyComplete);
JoinLobby(LobbyId);
}
function acceptInviteFromFriend()
{
`log(getFuncName());
if( GetPC() != none )
{
`log(GetFuncName()@"Accepting lobby invite; disconnecting from current server.", bDebug, 'DevLobby');
GetPC().ConsoleCommand( "disconnect" );
}
AddJoinLobbyCompleteDelegate(OnJoinLobbyComplete);
`log(GetFuncName()@"LobbyId="$UniqueNetIdToString(InviteLobbyId));
JoinLobby(InviteLobbyId);
}
/** JoinLobby() finished */
function OnJoinLobbyComplete(bool bWasSuccessful, const out array<ActiveLobbyInfo> LobbyList, int LobbyIndex, UniqueNetId LobbyUID, string Error)
{
local string ServerIPAddress;
`log(GetFuncName()@"bWasSuccessful="$bWasSuccessful@"LobbyIndex="$LobbyIndex@"LobbyUID="$UniqueNetIdToString(LobbyUID)@"Error="$Error, bDebug, 'DevLobby');
ClearJoinLobbyCompleteDelegate(OnJoinLobbyComplete);
if (bWasSuccessful)
{
// If we are in a game already, leave it and take us to the main lobby menu
//ConsoleCommand("disconnect");
if ( IsInLobby() )
{
LeaveLobby(CurrentLobbyId);
}
CurrentLobbyId = LobbyUID;
AddLobbyMemberStatusUpdateDelegate(OnLobbyMemberStatusUpdate);
ServerIPAddress = GetLobbyServerIP(CurrentLobbyId);
`log(GetFuncName()@"ServerIPAddress="$ServerIPAddress, bDebug, 'DevLobby');
if ((class'WorldInfo'.static.IsEOSBuild() && ServerIPAddress != "" && ServerIPAddress != "NULL") ||
(!class'WorldInfo'.static.IsEOSBuild() && ServerIPAddress != ""))
{
`log(GetFuncName()@"JoinServer called", bDebug, 'DevLobby');
JoinServer(ServerIPAddress, ZeroUniqueId);
QuitLobby();
}
NotifyLobbyStatusChanged(true);
}
}
/** Request to leave this lobby */
function bool QuitLobby()
{
local bool Success;
`log(GetFuncName()@"CurrentLobbyId="$UniqueNetIdToString(CurrentLobbyId), bDebug, 'DevLobby');
if ( IsInLobby() )
{
Success = LeaveLobby(CurrentLobbyId);
CurrentLobbyId = ZeroUniqueId;
ClearLobbyMemberStatusUpdateDelegate(OnLobbyMemberStatusUpdate);
//MakeLobby(6, LV_Friends);
}
if(Success)
{
NotifyLobbyStatusChanged(false);
}
return success;
}
//@HSL_BEGIN - JRO - 7/16/2016 - Just use the PRI UniqueNetId on PC
function UniqueNetId GetMyId()
{
local UniqueNetId LoggedInPlayer;
GetUniquePlayerId(0, LoggedInPlayer);
return LoggedInPlayer;
}
//@HSL_END
/*********************************************************************************************
* @name Game Invites
********************************************************************************************* */
native function bool JoinServer(string ServerIP, UniqueNetId ServerId);
native function bool SetLobbyServer(UniqueNetId LobbyId, UniqueNetId ServerUID, string ServerIP);
native function bool GetServerConnected();
native function string GetLobbyServerIP(const out UniqueNetId LobbyId);
native function string GetConnectedServerIP();
native function string AppendPasswordToURL(string URL, string Password);
native function RejectInvite(UniqueNetId LobbyId, UniqueNetId FriendId);
/** Called on lobby owner when new listen server game is started */
function bool LobbyJoinGame(optional string ServerIP)
{
`log(GetFuncName()@"ServerIP="$GetLobbyServerIP(CurrentLobbyId), bDebug, 'DevLobby');
if ( !IsInLobby() )
{
return false;
}
else if ( !GetServerConnected() || !Outer.CachedAuthInt.IsReady() )
{
`log(GetFuncName()@"Server is not connected or auth is not ready.", bDebug, 'DevLobby');
if (!bWaitingForServer)
{
PendingServerIP = ServerIP;
bWaitingForServer = true;
Outer.CachedAuthInt.AddAuthReadyDelegate(LobbyJoinGameDelegate);
`log(GetFuncName()@"Waiting for server PendingServerIP=" @ PendingServerIP, bDebug, 'DevLobby');
}
return true;
}
//Make sure that delegate is always cleaned up, no matter what
LobbyJoinGameDelegate();
return true;
}
/** Called when AuthReady is complete, or immediately if Auth is already ready */
function LobbyJoinGameDelegate()
{
local UniqueNetId ServerId;
`log(GetFuncName()@"Done waiting for server PendingServerIP=" @ PendingServerIP, bDebug, 'DevLobby');
bWaitingForServer = false;
Outer.CachedAuthInt.ClearAuthReadyDelegate(LobbyJoinGameDelegate);
Outer.CachedAuthInt.GetServerUniqueId(ServerId);
//Blank IP address means we own the lobby and we're joining our local listen server
SetLobbyServer(CurrentLobbyId, ServerId, PendingServerIP);
PendingServerIP = "";
}
/* Called when a lobby member or owner joins a dedicated server,
if a lobby owner, it takes the lobby, if not, leave the lobby */
function bool LobbyJoinServer(string ServerIP)
{
`log(GetFuncName()@"ServerIP="$ServerIP, bDebug, 'DevLobby');
if (IsLobbyOwner())
{
//return LobbyJoinGame(ServerIP);
return SetLobbyServer(CurrentLobbyId, ZeroUniqueId, ServerIP);
}
else
{
//If we're in a lobby but not the owner, leave the lobby since we're joining
//a separate server
QuitLobby();
return false;
}
}
/** Called when the lobby owner starts a map */
function OnLobbyJoinGame(const out array<ActiveLobbyInfo> LobbyList, int LobbyIndex, UniqueNetId ServerId, string ServerIP)
{
local bool bSuccess;
if (IsLobbyOwner())
{
return;
}
`log(GetFuncName()@"LobbyIndex="$LobbyIndex@"ServerId="$UniqueNetIdToString(ServerId)@"ServerIp="$ServerIp, bDebug, 'DevLobby');
//JoinServer handles the case of trying to join a server to which you are already connected
//returns true in that case, and if the join attempt start successfully
bSuccess = JoinServer(ServerIP, ServerId);
QuitLobby();
`log(GetFuncName()@"bSuccess="$bSuccess@"ServerIP="$ServerIP, bDebug, 'DevLobby');
}
/*********************************************************************************************
* @name Lobby Matchmaking (aka Find Match)
********************************************************************************************* */
/**
* Kicks off a search for available lobbies, matching the specified filters, triggering callbacks when done
*/
function bool FindLobbies(optional int MaxResults=32, optional array<LobbyFilter> Filters, optional array<LobbySortFilter> SortFilters,
optional int MinSlots, optional ELobbyDistance Distance=LD_Best)
{
AddFindLobbiesCompleteDelegate(FindLobbiesComplete);
return super.FindLobbies(MaxResults, Filters, SortFilters, MinSlots, Distance);
}
/** Callback when FindLobbies finished */
function FindLobbiesComplete(bool bWasSuccessful, const out array<BasicLobbyInfo> LobbyList)
{
ClearFindLobbiesCompleteDelegate(FindLobbiesComplete);
if (bWasSuccessful && LobbyList.length > 0)
{
AddJoinLobbyCompleteDelegate(OnJoinLobbyComplete);
`log("Starting join of party" @ UniqueNetIdToString(LobbyList[0].LobbyUID));
JoinLobby(LobbyList[0].LobbyUID);
}
else if (bWasSuccessful)
{
`log("Unable to find a matching lobby.");
NotifyUnsuccessfulSearch();
}
else
{
`log("Find lobbies failed.");
}
}
//@UI Notify the menu manager that the search was not successful
function NotifyUnsuccessfulSearch()
{
local PlayerController PC;
PC = GetPC();
if(PC != none)
{
PC.NotifyUnsuccessfulSearch();
}
}
function NotifyLobbyStatusChanged(bool bInLobby)
{
local PlayerController PC;
PC = GetPC();
if(PC != none)
{
PC.OnLobbyStatusChanged(bInLobby);
}
}
/*********************************************************************************************
* @name Lobby Settings
********************************************************************************************* */
native function string GetLobbyData( int LobbyIndex, string Key );
function SetLobbyData( string Key, string Value )
{
if ( !IsInLobby() )
{
return;
}
SetLobbySetting(CurrentLobbyId, Key, Value);
}
function bool SetVisibility( int VisibilityIndex )
{
if ( IsInLobby())
{
LobbyVisibility = ELobbyVisibility(VisibilityIndex);
return SetLobbyType( CurrentLobbyId, ELobbyVisibility(VisibilityIndex) );
}
return false;
}
/*********************************************************************************************
* @name Messages / Chat
* @todo: We should be using LobbyData instead of messages to broadcast UI info about the lobby and it's members
********************************************************************************************* */
function PlayerController GetPC()
{
local WorldInfo WI;
WI = class'WorldInfo'.static.GetWorldInfo();
return WI.GetALocalPlayerController();
}
event ConsolePrint(string message)
{
GetPC().ClientMessage(message);
}
//event ConsoleCommand( string Command )
//{
// GetPC().ConsoleCommand( Command );
//}
/** Recieve from other lobby member */
function OnLobbyReceiveMessage(const out array<ActiveLobbyInfo> LobbyList, int LobbyIndex, int MemberIndex, string Type, string Message)
{
local UniqueNetId MemberId;
local string Nickname;
//`log(GetFuncName()@"LobbyIndex="$LobbyIndex@"MemberIndex="$MemberIndex@"Type="$Type@"Message="$Message, bDebug, 'DevLobbyMsg');
MemberId = LobbyList[LobbyIndex].Members[MemberIndex].PlayerUID;
if (MemberId != ZeroUniqueId)
{
Nickname = UniqueNetIdToPlayerName(MemberId);
if (Nickname == "")
{
Nickname = "Unknown Nickname";
}
ConsolePrint(Message);
}
}
/** Send message */
function bool LobbyMessage(string Message)
{
//`log(GetFuncName()@"Message="$Message, bDebug, 'DevLobbyMsg');
if ( !IsInLobby() )
{
return false;
}
return SendLobbyMessage(CurrentLobbyId, Message);
}
/*********************************************************************************************
* @name Debugging
********************************************************************************************* */
event TestFindLobbies()
{
`log("Attempting to find lobbies.");
FindLobbies();
}
function string GetLobbyURLString()
{
local ActiveLobbyInfo LobbyInfo;
local string LobbyURLString;
local LobbyMember Member;
local int Index;
if (!GetCurrentLobby(LobbyInfo))
{
return "";
}
foreach LobbyInfo.Members(Member, Index)
{
if (Member.PlayerUID != LoggedInPlayerId)
{
`log("LobbyURLString:"@UniqueNetIdToString(Member.PlayerUID));
LobbyURLString $= "?party"$Index$"=" $ UniqueNetIdToString(Member.PlayerUID);
}
}
//LobbyURLString $= "?party3=0x0110000100122A11";
`log("LobbyURLString:"@LobbyURLString);
return LobbyURLString;
}
function bool GetCurrentLobby(out ActiveLobbyInfo LobbyInfo)
{
local ActiveLobbyInfo i;
if ( IsInLobby() )
{
foreach ActiveLobbies(i)
{
if (i.LobbyUID == CurrentLobbyId)
{
LobbyInfo = i;
return true;
}
}
}
return false;
}
function string GetFriendNickname(UniqueNetId FriendId, optional bool IncludeSelf = true)
{
local String Nickname;
if (FriendId == ZeroUniqueId)
{
return "";
}
//For convinience, consider yourself to be your own friend
if (IncludeSelf && FriendId == LoggedInPlayerId)
{
return LoggedInPlayerName;
}
Nickname = UniqueNetIdToPlayerName(FriendId);
if (Nickname == "")
{
Nickname = "Non-friend";
}
return Nickname;
}
function SetServerPassword(string password)
{
if (IsLobbyOwner())
{
SetLobbyData("Password", password);
}
}
defaultproperties
{
bDebug=TRUE
bWaitingForServer=FALSE
}
`endif