Unreal Hub/Unreal Lab

[SeSAC, Unreal Network] 2025. 04. 08

likepint 2025. 4. 8. 10:38


RPC (Remote Procedure Call)

UFUNCTION(Server, Reliable, Unreliable)
UFUNCTION(Client, Reliable, Unreliable)
UFUNCTION(NetMulticast, Reliable, Unreliable)

출처 : 언리얼 엔진의 RPC ❘ 언리얼 엔진 5.5 문서 ❘ Epic Developer Community
출처 : 언리얼 엔진의 RPC ❘ 언리얼 엔진 5.5 문서 ❘ Epic Developer Community

 

클라이언트에서 서버로 요청 -> 서버의 서버RPC함수 -> 클라이언트 RPC 호출 -> 클라이언트 함수

멀티캐스트의 경우 클라이언트 RPC 호출시 모든 클라이언트에게 전송

 

ServerRPC

UCLASS()
class SESAC_NETWORK_API ACNetActor : public AActor
{
	GENERATED_BODY()
	
public:
	UFUNCTION(Reliable, Server)
	void ServerRPC_ChangeColor(const FLinearColor InColor);
	void ServerRPC_ChangeColor_Implementation(const FLinearColor InColor);

};
void ACNetActor::BeginPlay()
{
	Super::BeginPlay();
	
	Mat = MeshComp->CreateDynamicMaterialInstance(0);

	if (HasAuthority())
	{
		FTimerHandle handle;

		auto lambda = [&]()
			{
				FLinearColor MatColor = FLinearColor::MakeRandomColor();

				//OnRep_ChangeMatColor();
				ServerRPC_ChangeColor(MatColor);
			};

		GetWorld()->GetTimerManager().SetTimer(handle, lambda, 1, true);
	}

}

void ACNetActor::ServerRPC_ChangeColor_Implementation(const FLinearColor InColor)
{
	if (Mat)
		Mat->SetVectorParameterValue(TEXT("FloorColor"), InColor);

}

 

ClientRPC

UCLASS()
class SESAC_NETWORK_API ACNetActor : public AActor
{
	GENERATED_BODY()
	
public:
	UFUNCTION(Reliable, Server)
	void ServerRPC_ChangeColor(const FLinearColor InColor);
	void ServerRPC_ChangeColor_Implementation(const FLinearColor InColor);

	UFUNCTION(Client, Unreliable)
	void ClientRPC_ChangeColor(const FLinearColor InColor);
	void ClientRPC_ChangeColor_Implementation(const FLinearColor InColor);

};
void ACNetActor::ServerRPC_ChangeColor_Implementation(const FLinearColor InColor)
{
	if (Mat)
		Mat->SetVectorParameterValue(TEXT("FloorColor"), InColor);

	ClientRPC_ChangeColor(InColor);

}

void ACNetActor::ClientRPC_ChangeColor_Implementation(const FLinearColor InColor)
{
	if (Mat)
		Mat->SetVectorParameterValue(TEXT("FloorColor"), InColor);

}

클라이언트가 요청할 경우

 

NetMulticast

UCLASS()
class SESAC_NETWORK_API ACNetActor : public AActor
{
	GENERATED_BODY()
	
public:
	UFUNCTION(NetMulticast, Unreliable)
	void MulticastRPC_ChangeColor(const FLinearColor InColor);
	void MulticastRPC_ChangeColor_Implementation(const FLinearColor InColor);

};
void ACNetActor::ServerRPC_ChangeColor_Implementation(const FLinearColor InColor)
{
	//if (Mat)
	//	Mat->SetVectorParameterValue(TEXT("FloorColor"), InColor);

	//ClientRPC_ChangeColor(InColor);
	MulticastRPC_ChangeColor(InColor);

}

void ACNetActor::MulticastRPC_ChangeColor_Implementation(const FLinearColor InColor)
{
	if (Mat)
		Mat->SetVectorParameterValue(TEXT("FloorColor"), InColor);

}

 

TakePistol (네트워크)

UCLASS(config=Game)
class ASeSAC_NetworkCharacter : public ACharacter
{
	GENERATED_BODY()
    
public:
	/* ----------------- 멀티 플레이어 요소들 -----------------*/
	UFUNCTION(Server, Reliable)
	void ServerPRC_TakePistol();
	void ServerPRC_TakePistol_Implementation();

	UFUNCTION(NetMulticast, Reliable)
	void MulticastRPC_TakePistol(AActor* InPistolActor);
	void MulticastRPC_TakePistol_Implementation(AActor* InPistolActor);

};
void ASeSAC_NetworkCharacter::TakePistol(const FInputActionValue& Value)
{
	// 총을 소유하지 않았다면 일정 범위 안에 있는 총을 잡는다.

	// 필요 속성 : 총을 소유하고 있는지, 소유중인 총, 총을 잡을 수 있는 범위

	// 1. 총을 잡고 있지 않다면
	if (bHasPistol == true)	return;

	ServerPRC_TakePistol(); // 클라이언트에서 서버로 요청 (클라이언트)

}

// 클라이언트에게 요청받은 내용을 처리 (서버)
void ASeSAC_NetworkCharacter::ServerPRC_TakePistol_Implementation()
{
	// 2. 월드에 있는 총을 모두 찾는다.
	for (const auto& pistol : PistolActors)
	{
		// 3. 총의 주인이 있다면 그 총은 검사하지 않는다.
		// 총이 없어질 수 있는 경우가 있다면 NULL체크 필요
		if (pistol->GetOwner() != nullptr) continue;

		// 4. 총과의 거리를 구한다.
		float distance = FVector::Dist(GetActorLocation(), pistol->GetActorLocation());

		// 5. 총이 범위 안에 있다면
		if (distance <= DistanceToGun)
		{
			// 6. 소유중인 총으로 등록한다.
			OwnedPistol = pistol;

			// 7. 총의 소유자를 자신으로 등록한다.
			pistol->SetOwner(this);

			// 8. 총 소유 상태를 변경한다.
			bHasPistol = true;

			MulticastRPC_TakePistol(pistol); // 요청 받은 내용을 검증 후 클라이언트에게 명령 (서버)

			break;
		}
	} // for pistol

}

// 서버에서 클라이언트에게 명령한 내용을 클라이언트에서 실행 (클라이언트)
void ASeSAC_NetworkCharacter::MulticastRPC_TakePistol_Implementation(AActor* InPistolActor)
{
	// 9. 해당 총을 붙인다.
	AttachPistol(InPistolActor);

}

 

 

void ASeSAC_NetworkCharacter::AttachPistol(AActor* InPistol)
{
	auto mesh = InPistol->GetComponentByClass<UStaticMeshComponent>();
	mesh->SetSimulatePhysics(false);
	mesh->AttachToComponent(GunComp, FAttachmentTransformRules::SnapToTargetNotIncludingScale);

	//MainUI->ShowCrossHair(true);

	if (IsLocallyControlled() and MainUI)
		MainUI->ShowCrossHair(true);

}

 

Replication 활성화