> 文章列表 > UE4/5多人游戏详解(八、游戏模式和游戏状态里的函数重写,插件内地图的地址做变量,做变量让按钮出现不同状态,插件内的所有代码)

UE4/5多人游戏详解(八、游戏模式和游戏状态里的函数重写,插件内地图的地址做变量,做变量让按钮出现不同状态,插件内的所有代码)

UE4/5多人游戏详解(八、游戏模式和游戏状态里的函数重写,插件内地图的地址做变量,做变量让按钮出现不同状态,插件内的所有代码)

目录

这里不写在插件里面,而是在游戏模式:

头文件:

Cpp文件:

更改ini文件

进入地图设置模式:

写插件里面,做一个变量:

写变量

然后更改函数MenuSet:

在子系统中做变量:

变量:

销毁的回调函数:

给按钮设置不输入

效果:

后续添加:

所有代码:

MultiPlayerSessionPlugin:

MultiPlayerSessionPlugin.h:

MultiPlayerSessionPlugin.cpp:

MultiPlayerSessionGISubsystem:

MultiPlayerSessionGISubsystem.h:

MultiPlayerSessionGISubsystem.cpp:

InPluginsMenu:

InPluginsMenu.h:

InPluginsMenu.cpp:

MultiPlayerSessionPlugin.Build.cs:

MultiPlayerSessionPlugin.uplugin:


游戏模式和游戏状态

GameMode和GameState在联网游戏中扮演着重要的角色,它们的函数可以帮助开发者管理游戏状态和玩家连接,实现联网游戏的功能。

这里不写在插件里面,而是在游戏模式:

创建这个类的原因是我们希望这个游戏模式是在Lobby这个地图使用的,而在这个Level(地图)中,每一次玩家加入和离开,我们都需要专用的函数去使用

 

这个创建到content里面,而不是写在插件里面的:

然后

头文件:

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "LobbyGameMode.generated.h"/*** */
UCLASS()
class MOREPERSONTEST_API ALobbyGameMode : public AGameModeBase
{GENERATED_BODY()
public://重写: 登录成功后调用。这是第一个可以安全地在PlayerController上调用复制函数的地方。virtual void PostLogin(APlayerController* NewPlayer)override;//重写: 当具有PlaverState的控制器离开游戏或被销毁时调用virtual void Logout(AController* Exiting)override;
};

Cpp文件:

// Fill out your copyright notice in the Description page of Project Settings.#include "LobbyGameMode.h"
#include "GameFramework/GameStateBase.h"
#include "GameFramework/PlayerState.h"
#include "MorePersonTestCharacter.h"void ALobbyGameMode::PostLogin(APlayerController* NewPlayer)
{//调用父类Super::PostLogin(NewPlayer);//GameState用于将游戏状态相关属性复制到所有客户端。if (GameState){//获取玩家数量int32 NumberOfPlayer = GameState.Get()->PlayerArray.Num();if (GEngine){GEngine->AddOnScreenDebugMessage(1, 15, FColor::Blue, FString::Printf(TEXT("Now PlayerNum is %d"), NumberOfPlayer));//获取状态->详情可以向父类看过去APlayerState* playerState =NewPlayer->GetPlayerState<APlayerState>();if (playerState){//获取名字FString playerName =playerState->GetPlayerName();GEngine->AddOnScreenDebugMessage(-1, 15, FColor::Cyan, FString::Printf(TEXT("%s join game"), *playerName));}}}
}void ALobbyGameMode::Logout(AController* Exiting)
{//调用父类Super::Logout(Exiting);APlayerState* playerState = Exiting->GetPlayerState<APlayerState>();if (playerState){//现在的人数int32 NumberOfPlayer = GameState.Get()->PlayerArray.Num();GEngine->AddOnScreenDebugMessage(1, 15, FColor::Blue, FString::Printf(TEXT("Now PlayerNum is %d"), NumberOfPlayer-1));//获取名字FString playerName = playerState->GetPlayerName();GEngine->AddOnScreenDebugMessage(-1, 15, FColor::Cyan, FString::Printf(TEXT("%s out the game"), *playerName));}
}

更改ini文件

 

进入地图设置模式:

将游戏模式创建蓝图类,然后换蓝图的pawn上去,之后放到lobby的地图里面:

 

 

 

写插件里面,做一个变量:

写变量

我们之前进入这个Lobby的地图的时候,使用的是Lobby地图的地址

但这个是一个插件,那么,我们就需要考虑到不同项目有不同的地图,所以这里我们需要做一个全新的变量:

在菜单类中:

 

然后更改函数MenuSet

我们需要在MenuSet的后面添加这个地址:

 不用忘记更改cpp中的文件,然后添加这个:

 在完成这些之后,我们在下面的创建会话的回调函数就可以把绝对的地址引用改为这个变量:

 

在子系统中做变量:

变量:

 然后cpp里面

 实现销毁函数:

 代码:

void UMultiPlayerSessionGISubsystem::DeleteSession()
{if (!mySessionInterface.IsValid()){MultiPlayerOnDestroySessionComplete.Broadcast(false);return;}//句柄和添加委托DestroySessionCompleteDelegateHandle =mySessionInterface->AddOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegate);if (!mySessionInterface->DestroySession(NAME_GameSession)){//销毁会话失败mySessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);MultiPlayerOnDestroySessionComplete.Broadcast(false);}
}

销毁的回调函数:

 代码:

void UMultiPlayerSessionGISubsystem::onDestorySessionComplete(FName SessionName, bool bWasSuccessful)
{if (mySessionInterface){//清除mySessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);}//因为已经有一个会话了,所以要销毁会话然后在创建会话if (bWasSuccessful && bCreateSessionOnDestory){//重置初始值bCreateSessionOnDestory = false;//创建会话CreateSession(LastNumPublicConnects,LastMatchType);}MultiPlayerOnDestroySessionComplete.Broadcast(bWasSuccessful);}

给按钮设置不输入

 给几个回调函数做一个判断

 

 

 

效果:

这样就会变得透明

 

后续添加:

到这里为止,想必懂的都懂了,所以我就直接进行一下后续的添加(因为这个是插件,所以):

 

这里的

UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))

的意思是允许在蓝图中私有访问

所有代码:

分别是3个头文件,3个cpp文件,1个uplugin文件和一个cs文件:

MultiPlayerSessionPlugin:

MultiPlayerSessionPlugin.h:

// Copyright Epic Games, Inc. All Rights Reserved.#pragma once#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"class FMultiPlayerSessionPluginModule : public IModuleInterface
{
public:/** IModuleInterface implementation */virtual void StartupModule() override;virtual void ShutdownModule() override;
};
//需要更改的ini设置:
//更改:DefaultEngine.ini中的(添加到末尾):
//[/ Script / Engine.GameEngine]
//+ 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"//然后是DefaultGame.ini中的(添加到末尾):
//[/ Script / Engine.GameSession]
//MaxPlayers = 100

MultiPlayerSessionPlugin.cpp:

// Copyright Epic Games, Inc. All Rights Reserved.#include "MultiPlayerSessionPlugin.h"#define LOCTEXT_NAMESPACE "FMultiPlayerSessionPluginModule"void FMultiPlayerSessionPluginModule::StartupModule()
{// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}void FMultiPlayerSessionPluginModule::ShutdownModule()
{// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,// we call this function before unloading the module.
}#undef LOCTEXT_NAMESPACEIMPLEMENT_MODULE(FMultiPlayerSessionPluginModule, MultiPlayerSessionPlugin)

MultiPlayerSessionGISubsystem:

MultiPlayerSessionGISubsystem.h:

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"#include "Interfaces/OnlineSessionInterface.h"#include "MultiPlayerSessionGISubsystem.generated.h"//自定义委托,用于回调到菜单类
//动态多播
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiOnCreateSessionComplete, bool, bWasSuccessful);
//这里使用多播,而不是动态多播
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiOnFindSessionComplete, const TArray<FOnlineSessionSearchResult>& SessionResult, bool bWasSuccessful);
DECLARE_MULTICAST_DELEGATE_OneParam(FMultiOnJoinSessionComplete, EOnJoinSessionCompleteResult::Type Result);
//动态多播
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiOnDestroySessionComplete, bool, bWasSuccessful);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiOnStartSessionComplete, bool, bWasSuccessful);/*** */
UCLASS()
class MULTIPLAYERSESSIONPLUGIN_API UMultiPlayerSessionGISubsystem : public UGameInstanceSubsystem
{GENERATED_BODY()
public:UMultiPlayerSessionGISubsystem();////会话 --公开的链接函数//这里将输入玩家数量和会话的类型(用于匹配不同的会话)void CreateSession(int32 playerConnectNum, FString MatchType);//输入的是寻找会话的最大数量void FindSession(int32 findSessionMaxNum);//加入会话void JoinSession(const FOnlineSessionSearchResult& SessionResult);//删除void DeleteSession();//开始void StartSession();//将回调函数绑定到的菜单类的自定义委托//委托变量//UPROPERTY(BlueprintAssignable)FMultiOnCreateSessionComplete MultiPlayerOnCreateSessionComplete;FMultiOnFindSessionComplete  MultiPlayerOnFindSessionComplete;FMultiOnJoinSessionComplete  MultiPlayerOnJoinSessionComplete;FMultiOnDestroySessionComplete  MultiPlayerOnDestroySessionComplete;FMultiOnStartSessionComplete  MultiPlayerOnStartSessionComplete;protected://回调函数,将会绑定到委托(根据委托输入对应输入对象)void onCreateSessionComplete(FName SessionName, bool bWasSuccessful);void onFindSessionComplete(bool bWasSuccessful);void onJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);void onDestorySessionComplete(FName SessionName, bool bWasSuccessful);void onStartSessionComplete(FName SessionName, bool bWasSuccessful);private://会话接口IOnlineSessionPtr mySessionInterface;//会话设置的智能指针 查看上次的会话设置TSharedPtr<FOnlineSessionSettings> LastSessionSettings;//寻找会话的智能指针TSharedPtr<FOnlineSessionSearch> LastSessionSearch;//需要添加的委托,到时候要一一对应制作回调函数FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;FDelegateHandle CreateSessionCompleteDelegateHandle;//委托句柄FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate;FDelegateHandle FindSessionsCompleteDelegateHandle;//委托句柄FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;FDelegateHandle JoinSessionCompleteDelegateHandle;//委托句柄FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate;FDelegateHandle DestroySessionCompleteDelegateHandle;//委托句柄FOnStartSessionCompleteDelegate StartSessionCompleteDelegate;FDelegateHandle StartSessionCompleteDelegateHandle;//委托句柄//用于判断是否是在创建会话的时候正在销毁会话bool bCreateSessionOnDestory{ false };int32 LastNumPublicConnects;FString LastMatchType;
};

MultiPlayerSessionGISubsystem.cpp:

// Fill out your copyright notice in the Description page of Project Settings.#include "MultiPlayerSessionGISubsystem.h"
#include "OnlineSubsystem.h"
#include "OnlineSessionSettings.h"UMultiPlayerSessionGISubsystem::UMultiPlayerSessionGISubsystem():CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this,&UMultiPlayerSessionGISubsystem::onCreateSessionComplete)),FindSessionsCompleteDelegate(FOnFindSessionsCompleteDelegate::CreateUObject(this,&UMultiPlayerSessionGISubsystem::onFindSessionComplete)),JoinSessionCompleteDelegate(FOnJoinSessionCompleteDelegate::CreateUObject(this,&UMultiPlayerSessionGISubsystem::onJoinSessionComplete)),DestroySessionCompleteDelegate(FOnDestroySessionCompleteDelegate::CreateUObject(this,&UMultiPlayerSessionGISubsystem::onDestorySessionComplete)),StartSessionCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this,&UMultiPlayerSessionGISubsystem::onStartSessionComplete))
{//获取子系统IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get();if (Subsystem){//从子系统中获取了会话系统,并放到我们的会话接口指针里面mySessionInterface = Subsystem->GetSessionInterface();}
}void UMultiPlayerSessionGISubsystem::CreateSession(int32 playerConnectNum, FString MatchType)
{//判断会话系统是否有效if (!mySessionInterface.IsValid()){return;}//有会话则获取现有的会话auto ExistingSession = mySessionInterface->GetNamedSession(NAME_GameSession);//如果现有的会话并不是空的if (ExistingSession != nullptr){bCreateSessionOnDestory = true;LastNumPublicConnects = playerConnectNum;LastMatchType = MatchType;//删除游戏会话DeleteSession();}//在会话创建请求完成时触发委托CreateSessionCompleteDelegate,返回句柄到CreateSessionCompleteDelegateHandle,方便之后删除CreateSessionCompleteDelegateHandle = mySessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);//LastSessionSettings = MakeShareable(new FOnlineSessionSettings());//判断现在的接口是不是空的,是则返回true,不是则返回false【此游戏将仅限局域网,外部玩家无法看到,是true还是false】//直接在这里判断你是局域网还不是LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName()=="NULL"?true:false;//可用的连接数量是多少LastSessionSettings->NumPublicConnections = playerConnectNum;//是否允许加入线程LastSessionSettings->bAllowJoinInProgress = true;//是否允许通过玩家存在加入LastSessionSettings->bAllowJoinViaPresence = true;//该比赛是否在在线服务上面公开广告LastSessionSettings->bShouldAdvertise = true;//是否显示用户状态信息LastSessionSettings->bUsesPresence = true;//不同key和value的匹配,从现有会话设置中定义会话设置LastSessionSettings->Set(FName("MatchType"), MatchType, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);//用于防止不同的构建在搜索期间看到彼此LastSessionSettings->BuildUniqueId = 1;//支持api则使用LastSessionSettings->bUseLobbiesIfAvailable = true;//获取本地的第一个玩家控制器const ULocalPlayer* localPlayer = GetWorld()->GetFirstLocalPlayerFromController();//*localPlayer->GetPreferredUniqueNetId() 首选唯一网格ID//判断创建会话是否成功if (!mySessionInterface->CreateSession(*localPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings)){//创建失败//委托列表中删除委托,传入的是一个句柄(这个CreateSessionCompleteDelegateHandle在上面获取过)mySessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);//广播自定义委托:传给所有注册的回调函数falseMultiPlayerOnCreateSessionComplete.Broadcast(false);}
}void UMultiPlayerSessionGISubsystem::FindSession(int32 findSessionMaxNum)
{if (!mySessionInterface.IsValid()){return;}//会话接口委托列表添加委托,然后句柄获取FindSessionsCompleteDelegateHandle = mySessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate);LastSessionSearch = MakeShareable(new FOnlineSessionSearch);//配对服务返回的查询的最大数目LastSessionSearch->MaxSearchResults = findSessionMaxNum;//查询是否用于局域网匹配LastSessionSearch->bIsLanQuery = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;//SEARCH_PRESENCE :仅搜索存在会话(值为true/false)//QuerySettings :用于查找匹配服务器的查询LastSessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);//获取本地的玩家控制器const ULocalPlayer* playerControler = GetWorld()->GetFirstLocalPlayerFromController();//搜索与指定匹配的对话//GetPreferredUniqueNetId :检索首选的唯一网id。这是为了向后兼容不使用缓存唯一网络id逻辑的游戏if (!mySessionInterface->FindSessions(*playerControler->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef())){//寻找失败//清除mySessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);//因为失败了,所以传入的是一个空的数组和falseMultiPlayerOnFindSessionComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);}
}void UMultiPlayerSessionGISubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
{if (!mySessionInterface.IsValid()){//无效情况下//广播到所有绑定对象:UnknownErrorMultiPlayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);return;}//获取句柄和委托列表添加JoinSessionCompleteDelegateHandle =mySessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate);//加入会话const ULocalPlayer* localPlayer = GetWorld()->GetFirstLocalPlayerFromController();if (!mySessionInterface->JoinSession(*localPlayer->GetPreferredUniqueNetId(), NAME_GameSession, SessionResult)){//加入失败//清除委托mySessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle);//广播回调函数为未知错误MultiPlayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);}
}void UMultiPlayerSessionGISubsystem::DeleteSession()
{if (!mySessionInterface.IsValid()){MultiPlayerOnDestroySessionComplete.Broadcast(false);return;}//句柄和添加委托DestroySessionCompleteDelegateHandle =mySessionInterface->AddOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegate);if (!mySessionInterface->DestroySession(NAME_GameSession)){//销毁会话失败mySessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);MultiPlayerOnDestroySessionComplete.Broadcast(false);}
}void UMultiPlayerSessionGISubsystem::StartSession()
{
}void UMultiPlayerSessionGISubsystem::onCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{if (mySessionInterface){//这里是清除之前注册的回调函数,以便在下一次创建会话时不会重复调用(即委托句柄)mySessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle);}//传给所有注册的回调函数 bWasSuccessfulMultiPlayerOnCreateSessionComplete.Broadcast(bWasSuccessful);
}void UMultiPlayerSessionGISubsystem::onFindSessionComplete(bool bWasSuccessful)
{if (mySessionInterface){//清除mySessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);}//查找的会话数量if (LastSessionSearch->SearchResults.Num()<=0){//因为失败了,所以传入的是一个空的数组和falseMultiPlayerOnFindSessionComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);return;}//传入菜单MultiPlayerOnFindSessionComplete.Broadcast(LastSessionSearch->SearchResults, bWasSuccessful);
}void UMultiPlayerSessionGISubsystem::onJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{if (mySessionInterface){//执行完成,所以清除一下mySessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle);}//广播到菜单的onjoinsessionMultiPlayerOnJoinSessionComplete.Broadcast(Result);
}void UMultiPlayerSessionGISubsystem::onDestorySessionComplete(FName SessionName, bool bWasSuccessful)
{if (mySessionInterface){//清除mySessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);}//因为已经有一个会话了,所以要销毁会话然后在创建会话if (bWasSuccessful && bCreateSessionOnDestory){//重置初始值bCreateSessionOnDestory = false;//创建会话CreateSession(LastNumPublicConnects,LastMatchType);}MultiPlayerOnDestroySessionComplete.Broadcast(bWasSuccessful);}void UMultiPlayerSessionGISubsystem::onStartSessionComplete(FName SessionName, bool bWasSuccessful)
{
}

InPluginsMenu:

InPluginsMenu.h:

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Interfaces/OnlineSessionInterface.h"#include "InPluginsMenu.generated.h"/*** */
UCLASS()
class MULTIPLAYERSESSIONPLUGIN_API UInPluginsMenu : public UUserWidget
{GENERATED_BODY()
public://菜单设置 UFUNCTION(BlueprintCallable)void MenuSet(int32 NumberPublicConnect =4, FString TypeOfMatch= FString(TEXT("FreeForAll")),FString LobbyPath =FString(TEXT("/Game/Map/Lobby")));protected:virtual bool Initialize() override;//这是5.0的重载//如果是5.1无法使用的,请使用virtual void NativeDestruct() override//【我专门在5.1测试了一遍,找不到OnLevelRemovedFromWorld】;virtual void OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld) override;//子系统上的自定义委托的回调 如果绑定失败则加上UFUNCTIONUFUNCTION()void onCreateSession(bool bWasSuccessful);void onFindSession(const TArray<FOnlineSessionSearchResult>& SessionResult, bool bWasSuccessful);void onJoinSession(EOnJoinSessionCompleteResult::Type Result);UFUNCTION()void onDestroySession(bool bWasSuccessful);UFUNCTION()void onStartSession(bool bWasSuccessful);private://两个按钮,会和蓝图中的按钮链接,所以蓝图中的按钮要和c++中的一样名字UPROPERTY(meta=(BindWidget))class UButton* CreateSessionBotton;UPROPERTY(meta = (BindWidget))UButton* JoinSessionBotton;//点击创建会话按钮事件UFUNCTION()void CreateBottonClicked();//点击加入会话按钮事件UFUNCTION()void JoinBottonClicked();//移除控件void MenuTearDown();//这是最开始创建的类,在这里做一个变量//用于处理所有在线会话的子系统class UMultiPlayerSessionGISubsystem* MultiPlayerSessionSubsystem;private://初始化默认为4UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))int32 NumPublicConnect{4};//value值UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))FString MatchType{ TEXT("FreeForAll") };//大厅地址 初始化的空值FString pathToLobby{ TEXT("") };
};

InPluginsMenu.cpp:

// Fill out your copyright notice in the Description page of Project Settings.#include "InPluginsMenu.h"
#include "Components/Button.h"
#include "MultiPlayerSessionGISubsystem.h"
#include "OnlineSessionSettings.h"
#include "Interfaces/OnlineSessionInterface.h"
#include "OnlineSubsystem.h"void UInPluginsMenu::MenuSet(int32 NumberPublicConnect, FString TypeOfMatch, FString LobbyPath)
{//获取地址pathToLobby = FString::Printf(TEXT("%s?listen"), *LobbyPath);//私有变量初始化NumPublicConnect = NumberPublicConnect;MatchType = TypeOfMatch;//添加到视口AddToViewport();//设置可视SetVisibility(ESlateVisibility::Visible);//bIsFocusable设置为true是允许点击的时候受到焦点,是UserWidget里面定义的bIsFocusable = true;UWorld* world = GetWorld();if (world){APlayerController* playerControler = world->GetFirstPlayerController();if (playerControler){//FInputModeUIOnly 用于设置只允许ui响应用户输入的输入模式的数据结构FInputModeUIOnly inputModeData;//SetWidgetToFocus设置焦距//TakeWidget()获取底层的slate部件,不存在则构造它inputModeData.SetWidgetToFocus(TakeWidget());//设置鼠标在视口的行为,这里是不锁定inputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);//设置完毕输入模式的东西之后,在玩家控制器里面将设置好的输入模式设置到玩家控制器的输入模式playerControler->SetInputMode(inputModeData);//显示鼠标光标playerControler->SetShowMouseCursor(true);}}//获取现在的游戏实例判断是否存在UGameInstance* gameInstance = GetGameInstance();if (gameInstance){MultiPlayerSessionSubsystem =gameInstance->GetSubsystem<UMultiPlayerSessionGISubsystem>();}if (MultiPlayerSessionSubsystem){//添加动态委托 回调函数onCreateSessionMultiPlayerSessionSubsystem->MultiPlayerOnCreateSessionComplete.AddDynamic(this, &ThisClass::onCreateSession);MultiPlayerSessionSubsystem->MultiPlayerOnFindSessionComplete.AddUObject(this, &ThisClass::onFindSession);MultiPlayerSessionSubsystem->MultiPlayerOnJoinSessionComplete.AddUObject(this, &ThisClass::onJoinSession);MultiPlayerSessionSubsystem->MultiPlayerOnDestroySessionComplete.AddDynamic(this, &ThisClass::onDestroySession);MultiPlayerSessionSubsystem->MultiPlayerOnStartSessionComplete.AddDynamic(this, &ThisClass::onStartSession);}
}bool UInPluginsMenu::Initialize()
{if (!Super::Initialize()){return false;}if (CreateSessionBotton){//动态绑定CreateSessionBotton->OnClicked.AddDynamic(this,&UInPluginsMenu::CreateBottonClicked);}if (JoinSessionBotton){//动态绑定JoinSessionBotton->OnClicked.AddDynamic(this, &UInPluginsMenu::JoinBottonClicked);}return true;
}void UInPluginsMenu::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
{//这样就删除了控件和重置了输入模式和光标MenuTearDown();//执行父类 Super::OnLevelRemovedFromWorld(InLevel,InWorld);
}void UInPluginsMenu::onCreateSession(bool bWasSuccessful)
{if (bWasSuccessful){if (GEngine){GEngine->AddOnScreenDebugMessage(-1, 15, FColor::Blue, FString(TEXT("create success")));}UWorld* world = GetWorld();if (world){//将服务器跳转到新关卡world->ServerTravel(pathToLobby);}}else{if (GEngine){GEngine->AddOnScreenDebugMessage(-1, 15, FColor::Red, FString(TEXT("create Failed")));}//设置按钮的当前启用状态CreateSessionBotton->SetIsEnabled(true);}
}void UInPluginsMenu::onFindSession(const TArray<FOnlineSessionSearchResult>& SessionResult, bool bWasSuccessful)
{if (MultiPlayerSessionSubsystem == nullptr){return;}//遍历找到的会话数组for (auto Result : SessionResult){FString SettingsValue;//获取定义会话设置的key对应的value赋予SettingsValueResult.Session.SessionSettings.Get(FName(TEXT("MatchType")), SettingsValue);if (SettingsValue ==MatchType)//判断SettingsValue和MatchType是否一致,即找到了会话{//加入会话(在这里)MultiPlayerSessionSubsystem->JoinSession(Result);return;}}//如果失败了,或者知道的会话数量为0if (!bWasSuccessful ||SessionResult.Num()==0){JoinSessionBotton->SetIsEnabled(true);}
}void UInPluginsMenu::onJoinSession(EOnJoinSessionCompleteResult::Type Result)
{IOnlineSubsystem* onlineSubsystem = IOnlineSubsystem::Get();if (onlineSubsystem){//临时接口IOnlineSessionPtr TempMySessionInterface = onlineSubsystem->GetSessionInterface();if (TempMySessionInterface.IsValid()){//给予tempAddress地址FString tempAddress;TempMySessionInterface->GetResolvedConnectString(NAME_GameSession,tempAddress);//从游戏实例里面获取本地的第一个玩家控制器APlayerController* playerControler = GetGameInstance()->GetFirstLocalPlayerController();if (playerControler){//世界跳跃//旅行到不同的地图或IP地址。//在执行任何操作之前调用PreClientTravel事件。playerControler->ClientTravel(tempAddress, ETravelType::TRAVEL_Absolute);}}}//如果不是成功if (Result !=EOnJoinSessionCompleteResult::Success){JoinSessionBotton->SetIsEnabled(true);}
}void UInPluginsMenu::onDestroySession(bool bWasSuccessful)
{
}void UInPluginsMenu::onStartSession(bool bWasSuccessful)
{
}void UInPluginsMenu::CreateBottonClicked()
{//设置按钮的当前启用状态CreateSessionBotton->SetIsEnabled(false);if (MultiPlayerSessionSubsystem){//创建会话MultiPlayerSessionSubsystem->CreateSession(NumPublicConnect,MatchType);}
}void UInPluginsMenu::JoinBottonClicked()
{//设置按钮的当前启用状态JoinSessionBotton->SetIsEnabled(false);if (MultiPlayerSessionSubsystem){//寻找会话MultiPlayerSessionSubsystem->FindSession(10000);}}void UInPluginsMenu::MenuTearDown()
{//从父项中移除RemoveFromParent();UWorld* world = GetWorld();if (world){//获取玩家控制器APlayerController* playerControler = world->GetFirstPlayerController();if (playerControler){//创建默认的输入模式,然后设置为控制器FInputModeGameOnly inputModeData;playerControler->SetInputMode(inputModeData);//鼠标光标设置playerControler->SetShowMouseCursor(false);}}
}

MultiPlayerSessionPlugin.Build.cs:

// Copyright Epic Games, Inc. All Rights Reserved.using UnrealBuildTool;public class MultiPlayerSessionPlugin : ModuleRules
{public MultiPlayerSessionPlugin(ReadOnlyTargetRules Target) : base(Target){PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;PublicIncludePaths.AddRange(new string[] {// ... add public include paths required here ...});PrivateIncludePaths.AddRange(new string[] {// ... add other private include paths required here ...});PublicDependencyModuleNames.AddRange(new string[]{"Core","OnlineSubsystem","OnlineSubsystemSteam","UMG","Slate","SlateCore",// ... add other public dependencies that you statically link with here ...});PrivateDependencyModuleNames.AddRange(new string[]{"CoreUObject","Engine","Slate","SlateCore",// ... add private dependencies that you statically link with here ...	});DynamicallyLoadedModuleNames.AddRange(new string[]{// ... add any modules that your module loads dynamically here ...});}
}

MultiPlayerSessionPlugin.uplugin:

{"FileVersion": 3,"Version": 1,"VersionName": "1.0","FriendlyName": "MultiPlayerSessionPlugin","Description": "a multiplayer game use,join and connect in steam session","Category": "Other","CreatedBy": "LinJohn","CreatedByURL": "","DocsURL": "","MarketplaceURL": "","SupportURL": "","CanContainContent": true,"IsBetaVersion": false,"IsExperimentalVersion": false,"Installed": false,"Modules": [{"Name": "MultiPlayerSessionPlugin","Type": "Runtime","LoadingPhase": "Default"}],"Plugins": [{"Name": "OnlineSubsystem","Enabled": true},{"Name": "OnlineSubsystemSteam","Enabled": true}]
}

XP系统