728x90
반응형
- 정리
- 액터 리플리케이션 기초
- 액터 리플리케이션의 개요에 대한 학습
- C++을 활용한 프로퍼티 리플리케이션의 구현
- C++와 블루프린트간의 프로퍼티 리플리케이션 방식의 차이 비교
- 액터 리플리케이션 기초
- 액터 리플리케이션
- 특정 플레이어에 속한 액터의 정보를 네트웍 내 다른 플레이어에게 복제하는 작업
- 클라이언트-서버 모델에서는 대부분 서버에서 클라이언트로 전달함
- 서버만이 Authority를 가지기 때문
- 리플리케이션의 방법에는 크게 두 가지가 있음
- 프로퍼티 리플리케이션 : 속성 복제
- RPC(Remote Procedure Call) : 함수 호출
- 기본 액터의 로딩
- 클라이언트가 초기화 될 때 모든 액터 정보를 서버로부터 받는 것은 비효율적
- 따라서 기본 배경에 관련된 액터는 맵을 통해 스스로 로딩하도록 설계되어 있음
- 고정으로 제공하는 액터와 동적으로 생성하는 액터
- 고정으로 제공하는 액터의 예 : 레벨을 구성하는 배경 액터
- 앞으로 크게 변할 일이 없기 때문에 클라이언트에서 직접 초기 값을 로딩하는 것이 효율적이다.
- 동적으로 제공하는 액터의 예 : 플레이어 컨트롤러와 폰
- 고정으로 제공하는 액터의 예 : 레벨을 구성하는 배경 액터
- 고정 액터에 대해 NetLoadOnClient 속성을 체크해야 함 (기본값)
- 기본적으로 true로 설정되어 있음
- true로 설정된 액터들은 서버와 통신없이 클라이언트가 초기화될 때 자체적으로 로딩
- 액터의 리플리케이션 설정
- 고정으로 보여지는 액터 중, 게임 중 변경 사항이 발생하는 액터는 그 값을 전달해야 함
- 네트웍 데이터를 최소화하기 위해 변경 사항을 보내기보다, 변경을 유발한 속성 값을 전달함
- 그렇기 때문에 데이터 기반으로 설계하는것이 중요
- 이를 위해 액터의 Replicates 옵션을 체크해야 함
- 리플리케이션 프로퍼티(속성)의 지정
- 액터의 리플리케이션 속성을 참으로 지정
- bReplicates 속성을 true로 설정
- 네트웍으로 복제할 액터의 속성을 키워드로 지정
- UPROPERTY에 Replicated 키워드 설정
- GetLifetimeReplicatedProps 함수에 네트웍으로 복제할 속성을 추가
- #include “Net/UnrealNetwork.h” 헤더 파일 지정
- DOREPLIFETIME 매크로를 사용해 복제할 속성을 명시
- 여기서 Lifetime은 액터 채널의 Lifetime을 의미. 즉 활성화된 액터 채널로 전송할 복제될 속성을 의미
- 액터의 리플리케이션 속성을 참으로 지정
public:
// Lifetime 함수 추가
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
// Replicated 키워드를 붙여줘야 자동으로 언리얼 엔진의 네트워크 기능을 사용해서 다른 클라이언트로 복제가 된다.
UPROPERTY(Replicated)
float ServerRotationYaw;
float RotationRate = 30.0f;
- ABFountain.h
// Called every frame
void AABFountain::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 현재는 리슨 서버로 구성되어 있기 때문에 HasAuthority와 같은 체크 함수를 통해 클라이언트와 서버의 로직을 분리시켜줘야한다.
// 데디케이트 서버로 구성되어 있다면 서버로직만 구성하면 된다.
// Server
if (HasAuthority())
{
AddActorLocalRotation(FRotator(0.0f, RotationRate * DeltaTime, 0.0f));
ServerRotationYaw = RootComponent->GetComponentRotation().Yaw;
}
// Client
else
{
FRotator NewRotator = RootComponent->GetComponentRotation();
NewRotator.Yaw = ServerRotationYaw;
RootComponent->SetWorldRotation(NewRotator);
}
}
void AABFountain::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// ServerRotationYaw 속성을 추가하기 위해서 매크로 사용
// 기본적인 프로퍼티 리플리케이션 기능 구현할 수있다.
DOREPLIFETIME(AABFountain, ServerRotationYaw);
}
- ABFountain.cpp
- Replicated 키워드를 붙여줘야 자동으로 언리얼 엔진의 네트워크 기능을 사용해서 다른 클라이언트로 복제가 된다.
- 현재는 리슨 서버로 구성되어 있기 때문에 HasAuthority와 같은 체크 함수를 통해 클라이언트와 서버의 로직을 분리시켜줘야한다.
- 만약, 데디케이트 서버로 구성되어 있다면 서버로직만 구성해주면 된다.
- 다만 위의 코드는 매 Tick마다 서버로부터 받은 속성을 업데이트 해주었는데, 이렇게 되면 틱의 코드가 방대해지고, 상대방의 네트워크 전송 주기가 틱보다 느리다면 데이터를 받기 전에 틱이 여러번 호출돼 있어서 비효율적으로 동작할 수 있다.
- 리플리케이션 콜백 함수 호출
- 클라이언트에 속성이 복제될 때 콜백 함수가 호출되도록 구현
- UPROPERTY의 Replicated 키워드를 ReplicatedUsing 키워드로 변경
- ReplicatedUsing에 호출할 콜백 함수를 지정
- 호출될 콜백 함수는 UFUNCTION으로 선언해야 함
- 콜백 함수의 구현
- 일반적으로 OnRep_의 접두사를 가지는 이름 규칙을 가짐.
- 콜백 함수는 서버가 아닌 클라이언트에서만 호출됨
- 필요한 타이밍에만 해당 로직을 처리할 수 있어 효율적인 구현이 가능함
- 클라이언트에 속성이 복제될 때 콜백 함수가 호출되도록 구현
// ...
public:
// Lifetime 함수 추가
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
// 액터 리플리케이션을 진행하기 위해서는 액터 채널이라고 하는 특별한 채널을 사용한다.
virtual void OnActorChannelOpen(class FInBunch& InBunch, class UNetConnection* Connection) override;
// Replicated 키워드를 붙여줘야 자동으로 언리얼 엔진의 네트워크 기능을 사용해서 다른 클라이언트로 복제가 된다.
// ReplicatedUsing 키워드를 사용하고 함수를 지정해주면 서버에서 값이 변경이 되고, 클라이언트에 전달이 될 때 클라이언트에서는 이 함수가 자동으로 콜백함수가 호출된다.
UPROPERTY(ReplicatedUsing = OnRep_ServerRotationYaw)
float ServerRotationYaw;
UFUNCTION()
void OnRep_ServerRotationYaw();
- ABFountain.h
// ...
// 액터 리플리케이션을 진행하기 위해서는 액터 채널이라고 하는 특별한 채널을 사용한다.
// 클라이언트만 사용하며, 서버와의 포탈이 열렸다라고 생각하면 이해가 쉽다.
void AABFountain::OnActorChannelOpen(FInBunch& InBunch, UNetConnection* Connection)
{
AB_LOG(LogABNetwork, Log, TEXT("%s"), TEXT("Begin"));
Super::OnActorChannelOpen(InBunch, Connection);
AB_LOG(LogABNetwork, Log, TEXT("%s"), TEXT("End"));
}
// 콜백 함수
// 콜백 함수가 tick보다 더 적게 돌아가는 경우에는 보다 효율적으로 로직을 처리할 수 있다.
void AABFountain::OnRep_ServerRotationYaw()
{
AB_LOG(LogABNetwork, Log, TEXT("Yaw : %f"), ServerRotationYaw);
FRotator NewRotator = RootComponent->GetComponentRotation();
NewRotator.Yaw = ServerRotationYaw;
RootComponent->SetWorldRotation(NewRotator);
}
- ABFountain.cpp
- 네트워크로 전달될 때마다 콜백함수의 로그가 찍히는 것을 볼 수 있다.
- 또한, OnActorChannelOpen함수를 통해 서버와의 연결이 된 것을 보고 리플리케이션이 진행되는 것을 볼 수 있다.
- BP에서도 변수를 생성하고 Replication을 Replicated나 RepNotify로 변경하면 Functions에 OnRep이라는 접두사를 가진 함수가 생성되게 된다.
- 해당 함수는 BP에서 호출할 수 없고 오직 구현만 가능하다.
- 위 BP의 경우 클라이언트는 0에서 10으로 변경되는 단 한번만 로그가 찍히게 되고, 서버는 매초 10이라는 로그가 찍히게 된다.
해당 포스트는 인프런의 <이득우의 언리얼 프로그래밍 Part3 - 네트웍 멀티플레이어 프레임웍의 이해>
강의를 수강하고 정리한 내용입니다.
이득우의 언리얼 프로그래밍 Part3 - 네트웍 멀티플레이 프레임웍의 이해 강의 | 이득우 - 인프런
이득우 | 또 하나의 언리얼 엔진이라고도 불리는 네트웍 멀티플레이어 프레임웍을 학습합니다. 네트웍 멀티플레이어 게임을 제작할 때 반드시 알아야 하는 주요 개념, 내부 동작 원리, 최적화
www.inflearn.com
728x90
'공부 > 이득우의 언리얼 프로그래밍' 카테고리의 다른 글
[Study] Part 3 - 액터 리플리케이션 로우레벨 플로우 (7/15) (0) | 2024.08.21 |
---|---|
[Study] Part 3 - 액터 리플리케이션 빈도와 연관성 (6/15) (0) | 2024.08.20 |
[Study] Part 3 - 액터의 역할과 커넥션 핸드셰이킹 (4/15) (0) | 2024.08.14 |
[Study] Part 3 - 커넥션과 오너십 (3/15) (0) | 2024.08.12 |
[Study] Part 3 - 게임 모드와 로그인 (2/15) (0) | 2024.08.10 |