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함수 -> 클라이언트 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);
}