UE5.4多人模式下非主机客户端无法调用Door的ServerInteract RPC
UE5.4监听服务器模式下非主机客户端无法调用门Actor的ServerRPC问题
这是我制作的第一个带复制功能的多人游戏Actor,欢迎提供更优实现方案。
使用UE5.4版本,采用监听服务器(listen server)架构,包含两名玩家。当前正在开发可交互开关的门:玩家与门交互时,客户端调用ServerInteract服务器RPC,该RPC会更新门Actor的bOpen属性。此属性标记为ReplicatedUsing,本应同步到所有客户端并触发OnRep函数,根据bOpen状态播放开门或关门动画。
问题现象:主机客户端(客户端0)与门交互时,复制功能完全正常;但非主机客户端(客户端1)与门交互时,即便Actor拥有有效的NetOwner,ServerInteract RPC也无法被调用。
相关代码
Door.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "../InteractiveActor.h" #include "Door.generated.h" UCLASS() class ESCAPEGAME_API ADoor : public AInteractiveActor { GENERATED_BODY() public: // Sets default values for this actor's properties ADoor(); // Handle interaction virtual void ServerInteract_Implementation(APawn* InteractionSender) override; virtual void GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const override; UFUNCTION(BlueprintCallable) bool ToggleDoor(); UFUNCTION() void OnRep_bOpen(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; protected: UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Door) UAnimSequence* DoorOpening_Animation; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Door) UAnimSequence* DoorClosing_Animation; UPROPERTY(ReplicatedUsing=OnRep_bOpen ,EditAnywhere, BlueprintReadOnly, Category = Door) bool bOpen; public: UPROPERTY(EditAnywhere, category = Door) USkeletalMeshComponent* DoorSkeletalMesh; UPROPERTY(EditAnywhere, category = Door) USceneComponent* DoorRoot; };
Door.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "Door.h" #include "Net/UnrealNetwork.h" // Sets default values ADoor::ADoor() { PrimaryActorTick.bCanEverTick = false; DoorRoot = CreateDefaultSubobject<USceneComponent>(TEXT("DoorRoot")); SetRootComponent(DoorRoot); DoorSkeletalMesh = CreateDefaultSubobject<USkeletalMeshComponent>("DoorMesh"); DoorSkeletalMesh->SetupAttachment(DoorRoot); // Initiate variables bOpen = false; bReplicates = true; } // Called when the game starts or when spawned void ADoor::BeginPlay() { Super::BeginPlay(); } bool ADoor::ToggleDoor() { UE_LOG(LogTemp, Warning, TEXT("ToggleDoor : This actor has %s"), ( HasAuthority() ? TEXT("authority") : TEXT("no authority") )); bOpen = !bOpen; if (HasAuthority()) { DoorSkeletalMesh->PlayAnimation(bOpen ? DoorOpening_Animation : DoorClosing_Animation, false); } return bOpen; } void ADoor::OnRep_bOpen() { UE_LOG(LogTemp, Warning, TEXT("OnRep_bOpen Has authority : %s"), (HasAuthority() ? TEXT("yes") : TEXT("no"))); UE_LOG(LogTemp, Warning, TEXT("bOpen : %s"), (bOpen ? TEXT("yes") : TEXT("no"))); DoorSkeletalMesh->PlayAnimation(bOpen ? DoorOpening_Animation : DoorClosing_Animation, false); } void ADoor::ServerInteract_Implementation(APawn* player) { Super::ServerInteract_Implementation(player); UE_LOG(LogTemp, Warning, TEXT("Server : ServerInteract")); ToggleDoor(); } void ADoor::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(ADoor, bOpen); }
InteractiveActor.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "InteractiveActor.generated.h" UCLASS(Abstract) class ESCAPEGAME_API AInteractiveActor : public AActor { GENERATED_BODY() public: // Interact function UFUNCTION(Server, Reliable, WithValidation) virtual void ServerInteract(APawn* InteractionSender); virtual void ServerInteract_Implementation(APawn* InteractionSender); virtual bool ServerInteract_Validate(APawn* InteractionSender); };
InteractiveActor.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "InteractiveActor.h" void AInteractiveActor::ServerInteract_Implementation(APawn* InteractionSender) { UE_LOG(LogTemp, Warning, TEXT("ServerInteract with %s, Has authority: %s"), *InteractionSender->GetName(), (HasAuthority() ? TEXT("Yes") : TEXT("No"))); } bool AInteractiveActor::ServerInteract_Validate(APawn* InteractionSender) { return true; }
玩家F键触发的交互函数
void AEscapeGameCharacter::Interact() { UE_LOG(LogTemp, Warning, TEXT("AEscapeGameCharacter::Interact")); FVector StartLocation = FirstPersonCameraComponent->GetComponentLocation(); FVector EndLocation = FirstPersonCameraComponent->GetForwardVector() * 200 + StartLocation; FHitResult Hit; GetWorld()->LineTraceSingleByChannel(Hit, StartLocation, EndLocation, ECC_Visibility); DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, 5, 0, 5); if (!Hit.bBlockingHit) { return; } if (Hit.GetActor()->IsA(AInteractiveActor::StaticClass())) { AInteractiveActor* InteractiveActor = Cast<AInteractiveActor>(Hit.GetActor()); if (AEscapeGamePlayerController* controller = Cast<AEscapeGamePlayerController>(GetController())) { UE_LOG(LogTemp, Warning, TEXT("Net Rep Responsible Owner: %s"), (HasNetOwner() ? TEXT("Yes") : TEXT("No"))); InteractiveActor->SetOwner(this); InteractiveActor->ServerInteract(this); } } else { UE_LOG(LogTemp, Warning, TEXT("Hitted something")); } }
内容的提问来源于stack exchange,提问作者thacaout
相关产品推荐
相关产品推荐

