참고 자료: Unreal Engine Study :: 언리얼 네트워크 정리 (tistory.com)
// CCube.h
// 리플리 케이트 시킬 액터의 헤더의 멤버 변수 선언
UPROPERTY(Replicated)
FVector ReplicatedLocation;
-------------------------------------------------------------------------------------
// 리플리 케이트 시킬 멤버 변수를 선언하고, 바로 밑에 함수를 구현한다.
// 서버가 변수 값을 변경할 때, 그 변경 사항이 클라이언트에 복제되면서
// 지정된 함수가 클라이언트에서 호출된다.
// On_Rep가 호출되는 시점은 서버에서 리플리케이트가 완료된 상태이므로
// 클라입장에서 서버의 변수값으로 업데이트하는 코드가 필요하다
UPROPERTY(ReplicatedUsing = OnRep_ReplicatedTransform)
FTransform ReplicatedTransform;
UFUNCTION()
void OnRep_ReplicatedTransform(); // 이 함수는 클라이언트에서만 실행된다.
-------------------------------------------------------------------------------------
// 클라이언트에서 서버로 호출할 함수, 구현 내용은 ServerSpawnCube_Implementation()에 작성
// 클라이언트에서 호출하고, 구현 내용은 서버에만 적용됨
// Server: 함수가 서버에서 실행됨을 나타냄
// Reliable: 함수 호출이 반드시 전달됨을 보장
// WithValidation: 함수 호출 전에 유효성 검사를 수행
// 서버든 클라이언트든 ServerSpawnCube()을 호출하면 둘 다 서버에서 ServerSpawnCube_Implementation()가 실행됨
UFUNCTION(Server, Reliable, WithValidation)
void ServerSpawnCube();
void ServerSpawnCube_Implementation();
bool ServerSpawnCube_Validate();
-------------------------------------------------------------------------------------
// 서버에서 클라이언트로 호출하는 함수
// Client로 지정된 함수는 특정한 하나의 컨트롤러->GetPawn()을통해
// 하나의 클라이언트에게만 함수 호출을 한다.
// 서버에서 호출하고, 구현 내용은 지정된 하나의 클라이언트에만 적용된다.
// 사용 예시) 한 플레이어에게만 적용되는 이벤트 (보상 지급)
// 특정 클라이언트의 컨트롤러를 명시적으로 지정하지 않으면 함수 호출은 무시됨
UFUNCTION(Client, Reliable)
void ClientSpawnCube();
void ClientSpawnCube_Implementation();
-------------------------------------------------------------------------------------
// 서버에서 모든 클라이언트로 호출하는 함수 (NetMulticast)
// 서버에서 호출하고, 구현 내용은 클라이언트에만 적용된다.
UFUNCTION(NetMulticast, Reliable)
void AllClientSpawnCube();
void AllClientSpawnCube_Implementation();
-------------------------------------------------------------------------------------
// CCube.cpp
#include "Net/UnrealNetwork.h" // 리플리케이트 시킬 액터의 CPP에 추가하는 헤더
bReplicates = true; // 리플리 케이트를 적용할 지 결정하는 bool 변수 정적, 동적으로 설정 가능하다. (생성자, BeginPlay() 등)
HasAuthority() // 일반적으로 서버인지 아닌지 bool값을 반환하는 용도
// 특수한 경우로 서버가 아닌 클라이언트에서만 존재하는 액터의 경우 true값을 가질 수 있다.
IsLocallyControlled() // 컨트롤하고 있는 캐릭터에 대해 서버에서는 false, 클라이언트에서는 true 값을 반환한다
void ACCube::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ACCube, ReplicatedLocation); // 매크로(클래스, 리플리케이트 변수)
}
// GetLifetimeReplicatedProps는 따로 헤더에 선언할 필요 없이 cpp에 추가한다.
// 이 곳에 리플리케이트 시킬 변수들을 저장
// 추가하는 변수들은 자신의 클래스에서만 추가 가능하다. (외부 클래스에서 리플리케이트 변수 추가 불가능)
// 큐브를 스폰했을 때, 서버와 클라이언트에 모두 동시에 등장하여 동기화되는 코드
// CCube는 스태틱메시만 설정되어있는 간단한 클래스
// APracticeCharacter.h
UFUNCTION(Server, Reliable, WithValidation)
void ServerSpawnCube();
void ServerSpawnCube_Implementation();
bool ServerSpawnCube_Validate();
void InputQ();
-------------------------------------------------------------------------------------
// APracticeCharacter.cpp
void APracticeCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
PlayerInputComponent->BindAction("InputQ", IE_Pressed, this, &APracticeCharacter::InputQ);
}
void APracticeCharacter::ServerSpawnCube_Implementation()
{
FVector spawnLocation = GetActorLocation() + GetActorForwardVector() * 100.0f;
FRotator spawnRotation = GetActorRotation();
FActorSpawnParameters spawnParams;
spawnParams.Owner = this;
spawnParams.Instigator = GetInstigator();
ACCube* SpawnedCube = GetWorld()->SpawnActor<ACCube>(spawnLocation, spawnRotation, spawnParams);
if (SpawnedCube)
{
SpawnedCube->SetReplicates(true); // bReplicate = true;
SpawnedCube->SetReplicateMovement(true);
}
}
bool APracticeCharacter::ServerSpawnCube_Validate()
{
return true;
}
void APracticeCharacter::InputQ()
{
if (HasAuthority())
{
ServerSpawnCube_Implementation();
}
else
{
ServerSpawnCube();
}
}
// 추가해야하는 코드1 -> 배치 완료 전 까지는 '자신에게만' 보여야 함
// 추가해야하는 코드2 -> 스폰 하기 전에 머티리얼 변경을 통해 배치 가능하면 녹색, 불가능하면 붉은색