当前位置: 首页 > news >正文

TPS入门DAY01 服务器篇

1.实现代码

/* 头文件以及成员变量 */
#include "OnlineSubsystem.h"
#include "Interfaces/OnlineSessionInterface.h"  // 包含委托定义

DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);

public:
	/* 进入服务器的凭证,通过该凭证来加入同一个服务器 */
	IOnlineSessionPtr OnlineSessionInterface;

protected:
	/* 创建会话 */
	UFUNCTION(BlueprintCallable)
	void CreateGameSession();											

	/* 查找会话 */
	UFUNCTION(BlueprintCallable)
	void FindGameSession();													

	/* 创建完会话的回调函数 */
	void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful);
	/* 查找到会话的回调函数 */
	void OnFindSessionsComplete(bool bWasSuccessful);
	/* 加入会话时对应的回调函数 */
	void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);

private:
	/* 创建完成会话的委托 */
	FOnCreateSessionCompleteDelegate OnCreateSessionCompleteDelegate;
	/* 查找完成会话的委托 */
	FOnFindSessionsCompleteDelegate OnFindSessionsCompleteDelegate;
	/* 加入会话时的委托 */
	FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate;

	/* 存储搜索会话条件的容器,当用户通过凭证进入服务器时,并借凭证去搜索会话,将搜索会话的结果存储到该容器中的 SearchResults 中*/
	TSharedPtr<class FOnlineSessionSearch> SessionSearch;

头文件完整定义

.cpp实现文件

/*.cpp文件中的头文件*/
#include "OnlineSessionSettings.h"
#include "Online/OnlineSessionNames.h"

#include "Debug/MultiDebugHelper.h"
using namespace Debug;


/*构造函数*/
// 在线会话子系统
// Steam的桥梁作用,当使用Steam子系统是时,虽然每个程序实例都有自己的OnlinSessionInterface
// 但这些接口会连接到同一个Steam SDK
// 所有使用相同Steam配置的程序会看到相同的会话列表,创建的会话会注册到Steam服务器
// 所以IOnlineSessionInterface就是访问Steam在线服务的通行证,每个程序实例都会获取自己的通行证然后连接到同一个Steam服务器
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();
if (OnlineSub)
{
	// 获取会话管理接口
	OnlineSessionInterface = OnlineSub->GetSessionInterface();
	Print(FString::Printf(TEXT("OnlineSubsystem: %s"), *OnlineSub->GetSubsystemName().ToString()));
}
OnCreateSessionCompleteDelegate = FOnCreateSessionCompleteDelegate::CreateUObject(this, &AMenuSystemCharacter::OnCreateSessionComplete);
OnFindSessionsCompleteDelegate = FOnFindSessionsCompleteDelegate::CreateUObject(this, &AMenuSystemCharacter::OnFindSessionsComplete);
OnJoinSessionCompleteDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &AMenuSystemCharacter::OnJoinSessionComplete);


// 创建会话
void AMenuSystemCharacter::CreateGameSession()
{
	if (!OnlineSessionInterface.IsValid())
	{
		return;
	}
	
	// 1.搜索名为GameSession的会话并销毁
	auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);
	if (ExistingSession)
	{
		OnlineSessionInterface->DestroySession(NAME_GameSession);
	}

	// 2.绑定创建新会话完成时的委托
	OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(OnCreateSessionCompleteDelegate);
	
	// 3.配置会话参数
	TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());
	SessionSettings->bIsLANMatch = false;						// 使用互联网而非局域网
	SessionSettings->NumPublicConnections = 4;					// 最大玩家数
	SessionSettings->bAllowJoinInProgress = true;				// 允许中途加入
	SessionSettings->bAllowJoinViaPresence = true;				// 允许通过平台好友功能加入
	SessionSettings->bShouldAdvertise = true;					// 广播此会话
	SessionSettings->bUsesPresence = true;						// 使用平台的在线状态服务(Steam好友系统)
	SessionSettings->bUseLobbiesIfAvailable = true;				// 使用平台的聊天系统(Steam聊天室)
	SessionSettings->Set(FName("MatchType"), FString("FreeForAll"), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);

	const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
	OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings);
}

// 创建完会话的回调
void AMenuSystemCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{
	if (bWasSuccessful)
	{
		Print(FString::Printf(TEXT("Session '%s' created successfully"), *SessionName.ToString()),FColor::Green);
		UWorld* World = GetWorld();
		if (World)
		{
			World->ServerTravel("/Game/ThirdPerson/Maps/Lobby?listen");
		}
	}
	else
	{
		Print(FString::Printf(TEXT("Failed to create session '%s'"), *SessionName.ToString()), FColor::Red);
	}
}

// 查找游戏会话
void AMenuSystemCharacter::FindGameSession()
{
	if (!OnlineSessionInterface.IsValid())
	{
		return;
	}

	OnlineSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(OnFindSessionsCompleteDelegate);

	SessionSearch = MakeShareable(new FOnlineSessionSearch());
	SessionSearch->bIsLanQuery = false;
	SessionSearch->MaxSearchResults = 10000;
	SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);					// 启用Presence搜索

	const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
	// 提交会话请求
	OnlineSessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), SessionSearch.ToSharedRef());
}


// 找到会话的回调
void AMenuSystemCharacter::OnFindSessionsComplete(bool bWasSuccessful)
{
	if (!OnlineSessionInterface.IsValid())
	{
		return;
	}
	for (auto Result : SessionSearch->SearchResults)
	{
		FString ID = Result.GetSessionIdStr();
		FString User = Result.Session.OwningUserName;
		FString MatchType;
		Result.Session.SessionSettings.Get(FName("MatchType"), MatchType);
		Print(FString::Printf(TEXT("Id: %s, User: %s!"), *ID, *User));
		if (MatchType == FString("FreeForAll"))
		{
			Print(FString::Printf(TEXT("Joining Match Type '%s'"), *MatchType));
		}
		OnlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate);			// 添加委托到会话接口的委托列表

		const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();						//获取本地玩家指针
		// 第一个输入参数类型为 const FUniqueNetId &SearchingPlayerId
		// 第二个输入参数类型为 Fname SessionName
		// 第三个输入参数类型为 const FOnlineSessionSearchResult &DesiredSession,这里写 Result 即可
		OnlineSessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, Result);	// 调用在线接口函数加入会话
	}
}


// 会话加入成功的回调
void AMenuSystemCharacter::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
	if (!OnlineSessionInterface.IsValid())
		return;
	Print(TEXT("Session join complete"));
	FString Address;
	if (OnlineSessionInterface->GetResolvedConnectString(NAME_GameSession, Address))
	{
		Print(FString::Printf(TEXT("Connect string %s"), *Address));
		APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController();
		if (PlayerController)
		{
			PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute);
		}
	}
}

打印代码

#pragma once

#include "CoreMinimal.h"

/**
 * 
 */
namespace Debug
{
	static void Print(const FString& Message, FColor Color = FColor::Blue)
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage(-1, 5.f, Color, Message);
			UE_LOG(LogTemp, Warning, TEXT("%s"), *Message);
		}
	}
};

2.实现细节

/*DefaultEngine.ini*/

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

[OnlineSubsystem]
DefaultPlatformService=Steam

[OnlineSubsystemSteam]
bEnabled=true
SteamDevAppId=480
bInitServerOnClient=true

[/Script/OnlineSubsystemSteam.SteamNetDriver]
NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"

两台电脑,两个Steam账号,双方互相为好友,且下载地区一直,例如我是中国-上海,联机的账号也必须是中国-上海,此外好友双方必须为在线状态;

3.蓝图

4.具体逻辑

就以微信群聊打比方吧,把会话比作微信群聊,steam通行证OnlineSessionInterface就是微信;

然后在微信中创建了群聊(会话),创建群聊成功后,你会跳转到群聊界面,其中创建群聊会有一系列设置,比如群聊名称(gamesession),仅允许好友访问又比如需要回答问题才能加入群聊,并且设置了这个群聊的键值对组合。

搜索群聊的时候也是根据这些信息去匹配搜索到的群聊,如果群聊的Result.Session.SessionSettings.Get(FName("MatchType"), MatchType);

即群聊名字为gamesession的键(Key)对应的value就是FreeForAll说明该会话查找成功,下一步就是申请加入群聊了,通过获取群聊名称为gamesession的地址,来加入群聊

大致逻辑就是这些

相关文章:

  • US112S-ASEMI智能家居专用US112S
  • 深入理解 IntersectionObserver:让前端滚动监听更高效
  • [AI] 如何将 ComfyUI 的作图能力融合到 OpenWebUI
  • Scala:大数据时代的多面手
  • stm32面试
  • Go+Gin实现安全多文件上传:带MD5校验的完整解决方案
  • 使用Java爬虫按关键字搜索淘宝商品?
  • 用matlab探索卷积神经网络(Convolutional Neural Networks)-3
  • 2025年- G33-Lc107-150. 评估逆波兰表示法--java版
  • 电脑办公之文件(夹)操作
  • CentOS-查询实时报错日志-查询前1天业务报错gz压缩日志
  • 当AI开始“思考“:揭秘大语言模型的文字认知三部曲题
  • 使用RKNN进行yolo11-cls部署
  • Java的Stream流
  • 大量意图识别方案
  • 目标跟踪综合知识
  • 前端抽象化,打破框架枷锁:Http请求也许该一样
  • 数字化转型国家标准- GB/T 45341-2025《数字化转型管理 参考架构》
  • ThreadLocal 深度解析
  • 解决Certificate verification failed错误
  • 宇树科技王兴兴:第一桶金来自上海,欢迎上海的年轻人加入
  • 碧桂园境外债务重组:相当于现有公众票据本金额逾50%的持有人已加入协议
  • 国家出口管制工作协调机制办公室部署开展打击战略矿产走私出口专项行动
  • 国博馆刊|北朝至唐初夏州酋豪李氏家族的发展与身份记忆
  • 七大交响乐团在沪“神仙斗法”,时代交响奏出何等时代新声
  • 丰田汽车:美国关税或导致4、5月损失1800亿日元,新财年净利润下滑三成