์์ ํฌ์คํ
์์ LAN ์ฐ๊ฒฐ์ ๊ตฌํํ ๋, ์ง์ IP์ฃผ์๋ฅผ ์
๋ ฅํ์ฌ ๋ค๋ฅธ PC์ ๊ฒ์์ ์ ์ํ๋ค.
ํ์ง๋ง ์ค์ ์จ๋ผ์ธ ํ๊ฒฝ์์ ๊ฒ์์ ์ ์ํ ๋๋ ๋ค๋ฅธ ์ ์ ์ IP์ฃผ์๋ฅผ ๋ชจ๋ฅธ ์ฑ๋ก ๊ฒ์์ ์ ์ํ๋ค.
IP ์ฃผ์๋ฅผ ๋ชจ๋ฅด๋ ์ฑ๋ก ๋ค๋ฅธ ์ปดํจํฐ์ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด ๋๋ ค๋ฉด ์ค๊ฐ ๋จ๊ณ๊ฐ ํ์ํ๋ค.
์ฐ๋ฆฌ๊ฐ ๊ฒ์ ์ ์ํ ๋ ์ฌ์ฉํ ์ ์๋ ์ค๊ฐ ๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ด 2๊ฐ์ง๊ฐ ์๋ค.
- ์ ์ ๋ค์ IP๋ฅผ ๋ชจ์ ๊ด๋ฆฌํ๋ ๊ณ ์ ์ dedicate ์๋ฒ๋ก ์ฐ๊ฒฐ
- ์คํ์ด๋ xbox ๋ผ์ด๋ธ์ ๊ฐ์ ์จ๋ผ์ธ ํ๋ซํผ ์๋น์ค์์ ์ ๊ณตํ๋ ๋งค์น ๋ฉ์ดํน ๊ธฐ๋ฅ์ ํตํด ์ฐ๊ฒฐ
- - ๋งค์น๋ฉ์ดํน: ํ๋ ์ด์ด์ ์ธ์ ์ ๋งค์นํด ์ฃผ๋ ํ๋ก์ธ์ค (์ธ์ ์์ฑ, ์ธ์ ๊ฒ์, ์ธ์ ์ฐธ์ฌ, ์ธ์ ์๋ฉธ ๋ฑ๋ฑ)
- - ์ธ์ : ์ธ์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฒ์์ ์คํ์ค์ธ ๊ฒ์์ ์ธ์คํด์ค
์ฐ์ , 1๋ฒ์ ๊ณ ์ ์ dedicate ์๋ฒ์ฉ ์ปดํจํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ ์ ๊ฐ ๋์ด๋๋ฉด ๋์ด๋ ์๋ก ๊ตฌ์ถ ๋น์ฉ์ด ๋น์ธ์ง๋ค. ๋ณดํต ์ ์ ๊ฐ ๋ง์ ํฐ ํ์ฌ์์ ์ฑํํ๋ ์๋ฒ ๋ฐฉ์์ด๋ค.
๋ค์์ผ๋ก 2๋ฒ์ ์คํ์ด๋ xbox์ ๊ฐ์ ๊ฒ์ ํ๋ซํผ์์ ์์ ์ ํ๋ซํผ์ ๊ฒ์์ ์ ๊ณตํ๋ ๊ฒ์ ์๋ฒ์ด๋ค.
๊ฐ์ธ ๊ฐ๋ฐ์๋ ์์ ๊ฐ๋ฐ์ฌ๋ 2๋ฒ์ ์ ํํ ์ ๋ฐ์ ์์ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ 2๋ฒ์ ๋ฐฉ๋ฒ์๋ ๋ฌธ์ ๊ฐ ์๋ค.
๋ง์ฝ ๊ฒ์์ ์คํ์๋ ์ฌ๋ฆฌ๊ณ xbox์๋ ์ฌ๋ฆฌ๊ณ ์ถ๋ค๋ฉด, ๊ฐ์ ๋์์ ํ๋ ์ฝ๋๋ฅผ ๊ฐ ํ๋ซํผ์ ๋ง๊ฒ ๋ฐ๋ก ์์ฑํด์ผ ํ๋ค.
๋๋ฌด๋ ๋นํจ์จ์ ์ด๊ณ ํผ๊ณคํ ์ผ์ด๋ค.
์ธ๋ฆฌ์ผ ์์ง์ ์ด๊ฒ์ ํด๊ฒฐํ๊ธฐ ์ํด ํ๋ซํผ์ ์๊ด์์ด ๋งค์น ๋ฉ์ดํน API๋ฅผ ์ฌ์ฉํ ์ ์๋ Abstraction Layer๋ฅผ ์ ๊ณตํ๋ค.
{ Unreal Engine Subsystem }
Unreal Engine Subsystem : ์จ๋ผ์ธ ํ๋ซํผ ์๋น์ค์ ๊ธฐ๋ฅ์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ค. ๋ฐ๋ผ์ ์จ๋ผ์ธ ํ๋ซํผ๋ง๋ค ์๋ก ์ฝ๋ฉํ ํ์์์ด ๊ฐ ํ๋ซํผ์ ๋งค์น ๋ฉ์ดํน API ํ๋์ ์ฝ๋๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋์์ค๋ค.
1. ๋ด ํ๋ก์ ํธ์ Online Subsystem Steam ์ฐ๊ฒฐํ๊ธฐ
1. Unreal ์์ “Online Subsystem Steam” ํ๋ฌ๊ทธ ์ธ์ ์ถ๊ฐํ๋ค.
2. ์ด ํ๋ฌ๊ทธ์ธ์ ์ ๊ทผํ๊ธฐ ์ํด (projectName).Build.cs
์์ PublicDependencyModuleNames.AddRange
์ "OnlineSubsystemSteam", "OnlineSubsystem”๋ฅผ ์ถ๊ฐํ๋ค.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", ... , "OnlineSubsystemSteam", "OnlineSubsystem" });
3. ์๋ํฐ์ vs๋ฅผ ์ข ๋ฃํ๊ณ ํ๋ก์ ํธ ํด๋ > Config > 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"
4. ํ๋ก์ ํธ ํด๋์์ Binaries, Saved, Intermediate ํด๋๋ฅผ ์ญ์ ํ๋ค. ๊ทธ๋ฆฌ๊ณ (projectName).uproject ํ์ผ์ ์ฐํด๋ฆญํด์ Generate visual studio project files ์ต์
์ ํด๋ฆญํ๋ค.
5. ํ๋ก์ ํธ๊ฐ ์ ์์ ์ผ๋ก ์คํ๋๋ฉด ์ฑ๊ณต!
2. Online Subsystem์ Access ํ๊ธฐ
์ด๊ธฐํ ๋จ๊ณ์์ OnlineSubsystem์ ์ ๊ทผํ์ฌ OnlineSessionInterface์ ๋ฐ์์จ๋ค.
OnlineSessionInterface๋ ๋งค์น ๋ฉ์ดํน ์ํ์ ๋ฌผ๋ก ํ๋ ์ด์ด๊ฐ ์จ๋ผ์ธ ๊ฒ์์ ์ฐพ์ ์ฐธ๊ฐํ ์ ์๋๋ก ํ๊ธฐ ์ํด ํ์ํ ๊ฒ๋ค์ ๋ฐฐํ์ ๋ฏธ๋ฆฌ ๊ตฌ์ฑํ๋ ํ๋ซํผ ์ ์ฉ ํจ์์ฑ์ ์ ๊ณตํ๋ค.
OnlineSubsystem์ ์ฌ์ฉํ๋๋ฐ ํ์์ ์ด๋ค.
AMenuSystemCharacter::AMenuSystemCharacter()
{
...
// OnlineSubsystem์ Access
IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get();
if (OnlineSubsystem)
{
// ์จ๋ผ์ธ ์ธ์
๋ฐ์์ค๊ธฐ
OnlineSessionInterface = OnlineSubsystem->GetSessionInterface();
if (GEngine)
{
// OnlineSubsystem ์ด๋ฆ ์ถ๋ ฅํ๊ธฐ
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, FString::Printf(TEXT("Found subsystem %s"), *OnlineSubsystem->GetSubsystemName().ToString()));
}
}
}
3. Session์ด ์์ฑ๋๋ฉด ํธ์ถ๋ Delegate์ Callbackํจ์๋ฅผ ๋ฐ์ธ๋ฉํ๊ธฐ.
(1) ์์ฑ์์์ Delegate ์ด๊ธฐํ ์์ Callback ํจ์ ๋ฑ๋ก
AMenuSystemCharacter::AMenuSystemCharacter()
: CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateSessionComplete))
{
...
}
(2) Callback ํจ์ ๊ตฌํ
void AMenuSystemCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccssful)
{
// ์ธ์
์์ฑ ์ฑ๊ณต!
if (bWasSuccssful)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, FString::Printf(TEXT("Created session : %s"), *SessionName.ToString()));
}
}
// ์ธ์ ์์ฑ ์คํจ
else
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, FString(TEXT("Failed to create session!")));
}
}
}
4. Session ์์ฑ
(1) OnlineSessionInterface๊ฐ ์ ํจํ์ง ์ฒดํฌํ๋ค.
if (!OnlineSessionInterface.IsValid())
{
// log
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, FString(TEXT("Game Session is invailed")));
}
return;
}
(2) ์ด๋ฏธ ์ธ์ ์ด ์กด์ฌํ๋ค๋ฉด ๊ธฐ์กด ์ธ์ ์ ์ญ์ ํ๋ค.
auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
OnlineSessionInterface->DestroySession(NAME_GameSession);
// Log
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Black, FString::Printf(TEXT("Destroy session : %s"), NAME_GameSession));
}
}
(3) ์ธ์ ์์ฑ ์๋ฃ ํ ํธ์ถ๋ delegate ๋ฆฌ์คํธ์ CreateSessionCompleteDelegate ์ถ๊ฐ
OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);
(4) ์ธ์ ์ต์ ์ธํ ํ๊ธฐ
TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());
SessionSettings->bIsLANMatch = false; // LAN ์ฐ๊ฒฐ
SessionSettings->NumPublicConnections = 4; // ์ต๋ ์ ์ ๊ฐ๋ฅ ์
SessionSettings->bAllowJoinInProgress = true; // Session ์งํ์ค์ ์ ์ ํ์ฉ
SessionSettings->bAllowJoinViaPresence = true; // ์ธ์
์ฐธ๊ฐ ์ง์ญ์ ํ์ฌ ์ง์ญ์ผ๋ก ์ ํ (์คํ์ presence ์ฌ์ฉ)
SessionSettings->bShouldAdvertise = true; // ํ์ฌ ์ธ์
์ ๊ด๊ณ ํ ์ง (์คํ์ ๋ค๋ฅธ ํ๋ ์ด์ด์๊ฒ ์ธ์
ํ๋ณด ์ฌ๋ถ)
SessionSettings->bUsesPresence = true; // ํ์ฌ ์ง์ญ์ ์ธ์
ํ์
SessionSettings->bUseLobbiesIfAvailable = true; // ํ๋ซํผ์ด ์ง์ํ๋ ๊ฒฝ์ฐ ๋ก๋น API ์ฌ์ฉ
(5) Local Player๋ฅผ ํธ์คํธ๋ก ์ค์ ํ์ฌ ํ์ฌ ์ธ์ ์์ฑํ๊ธฐ
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings);
์ ์ฒด ์ฝ๋
void AMenuSystemCharacter::CreateGameSession()
{
// Called when pressing the 1key
if (!OnlineSessionInterface.IsValid())
{
// log
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, FString(TEXT("Game Session is invailed")));
}
return;
}
// ์ด๋ฏธ ์ธ์
์ด ์กด์ฌํ๋ค๋ฉด ๊ธฐ์กด ์ธ์
์ ์ญ์ ํ๋ค
auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
OnlineSessionInterface->DestroySession(NAME_GameSession);
// Log
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Black, FString::Printf(TEXT("Destroy session : %s"), NAME_GameSession));
}
}
// ์ธ์
์์ฑ ์๋ฃ ํ ํธ์ถ๋ delegate ๋ฆฌ์คํธ์ CreateSessionCompleteDelegate ์ถ๊ฐ
OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);
// ์ธ์
์ธํ
ํ๊ธฐ
TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());
SessionSettings->bIsLANMatch = false; // LAN ์ฐ๊ฒฐ
SessionSettings->NumPublicConnections = 4; // ์ต๋ ์ ์ ๊ฐ๋ฅ ์
SessionSettings->bAllowJoinInProgress = true; // Session ์งํ์ค์ ์ ์ ํ์ฉ
SessionSettings->bAllowJoinViaPresence = true; // ์ธ์
์ฐธ๊ฐ ์ง์ญ์ ํ์ฌ ์ง์ญ์ผ๋ก ์ ํ (์คํ์ presence ์ฌ์ฉ)
SessionSettings->bShouldAdvertise = true; // ํ์ฌ ์ธ์
์ ๊ด๊ณ ํ ์ง (์คํ์ ๋ค๋ฅธ ํ๋ ์ด์ด์๊ฒ ์ธ์
ํ๋ณด ์ฌ๋ถ)
SessionSettings->bUsesPresence = true; // ํ์ฌ ์ง์ญ์ ์ธ์
ํ์
SessionSettings->bUseLobbiesIfAvailable = true; // ํ๋ซํผ์ด ์ง์ํ๋ ๊ฒฝ์ฐ ๋ก๋น API ์ฌ์ฉ
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings);
}
๊ฒฐ๊ณผ!
์ข์๋จ์ Debug Message์์ ์ธ์ ์ด ์์ฑ๋์์์ ํ์ธํ ์ ์๋ค.