참고 자료: 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 -> 스폰 하기 전에 머티리얼 변경을 통해 배치 가능하면 녹색, 불가능하면 붉은색