MoveTo_Implementation()이 꼭 필요할까?BlueprintNativeEvent를 호출하는 방식:UFUNCTION(BlueprintNativeEvent)로 정의된 함수는 내부적으로 ProcessEvent() 호출을 사용함ProcessEvent()는 다음을 판단함:MoveTo_Implementation() 실행✅ 즉, BP override가 없을 경우를 대비해 반드시 _Implementation()이 있어야 함.
없으면 링크 에러(LNK2019 등) 발생.
BlueprintImplementableEvent는 왜 안 될까?ProcessEvent()가 없음UFUNCTION(BlueprintImplementableEvent)
void MoveTo(FVector TargetLocation);
MoveTo()를 호출해도 ProcessEvent 경유로 BP 바디를 실행하지 않음BlueprintImplementableEvent는 서버 RPC가 안 되는가?BlueprintImplementableEvent는 Unreal이 리플렉션을 통해 C++ 호출 경로를 만들지 않기 때문입니다.
자세히 말하면:
BlueprintImplementableEvent는 C++에 구현이 전혀 없음ProcessEvent를 호출하지 않음 → 서버/클라이언트 분기 처리도 안 됨ProcessEvent()가 서버/클라이언트 분기 처리도 하느냐?UFUNCTION(Server, Reliable, BlueprintImplementableEvent) 같이 쓰면:// 이런 거
UFUNCTION(Server, Reliable, BlueprintImplementableEvent)
void Foo();
Unreal의 UObject::ProcessEvent(UFunction*, void* Params)는 단순히 함수를 실행하는 게 아님.
이 함수는 다음을 수행
FunctionFlags)FUNC_Net, FUNC_NetServer, FUNC_BlueprintCallable, etc.Role == ROLE_Authority, etc.)✅ 이 덕분에 Server, Reliable, BlueprintNativeEvent 함수는
C++에서 MoveTo() 한 줄만 호출해도 BP 바디가 서버에서 실행.
Unreal이 내부적으로 알아서 ProcessEvent() 경유로 네트워크 호출까지 처리.
BlueprintNativeEventMoveTo() 호출 → ProcessEvent 호출됨MoveTo_Implementation() 실행됨_Implementation()은 필수BlueprintImplementableEventMoveTo() 호출 시 → 바디가 전혀 없음따라서 어제 구상한 것과 다르게 BlueprintNativeEvent를 써야함.
virtual을 안 쓰는가? (BlueprintNativeEvent인데도)이건 언리얼 리플렉션 시스템의 설계상 이유입니다.
cpp
복사편집
class A {
public:
virtual void Foo(); // 다형성 위해 필요
};
이건 컴파일 타임에 vtable 기반으로 연결되죠.
cpp
복사편집
UFUNCTION(BlueprintNativeEvent)
void MoveTo(FVector TargetLocation);
UFunction 메타 정보를 통해 해당 함수가 BP에서 오버라이드 되었는지, 아니면 _Implementation()을 써야 하는지를 판단합니다.MoveTo()는 실제 호출 시, virtual을 안 써도 ProcessEvent()를 통해 다형성이 실현됩니다.즉:
| 일반 C++ 다형성 | Unreal 방식 |
|---|---|
virtual → vtable 기반 | UFUNCTION → UFunction + ProcessEvent 기반 |
| 컴파일 타임 디스패치 | 런타임 디스패치 (ProcessEvent) |
virtual 필수 | virtual 불필요, 오히려 붙이면 헷갈릴 수 있음 |
그래서 BlueprintNativeEvent로 바꾸고 virtual 삭제함
근데도 안됌.
왜 안될까?
BlueprintNativeEvent와 Server(RPC)는 동시에 쓰면 특별한 조건이 필요합니다Unreal은 다음과 같이 분리된 구조를 강제:
BlueprintNativeEvent → BP 오버라이드 가능Server → RPC이므로 실제 호출은 _Implementation()으로 이뤄짐즉, Server와 BlueprintNativeEvent는 함께 쓸 수 있지만, 함수 이름은 *_Implementation()까지 구성해야 정상 작동.
UFUNCTION(Server, Reliable, BlueprintNativeEvent)
void Server_MoveTo(FVector TargetLocation);
이때, Unreal은 내부적으로 Server_MoveTo_Implementation() 을 RPC 처리용으로, Server_MoveTo_Implementation_Implementation() 을 BP fallback으로 보려고 하다가 충돌이 남.
즉 , 이 조합은 Unreal 리플렉션 시스템에서 모호함을 유발
// 헤더
UFUNCTION(Server, Reliable)
void Server_MoveTo(FVector TargetLocation);
UFUNCTION(BlueprintImplementableEvent)
void OnMoveTo(FVector TargetLocation); // BP에서 오버라이드
// CPP
void UFlyingAIPathfindingBase::Server_MoveTo_Implementation(FVector TargetLocation)
{
OnMoveTo(TargetLocation); // BP 함수 호출
}
✅ 가장 안정적인 구조
OnMoveTo() → BP에서 자유롭게 이동 처리 구현 가능근데 OnMoveTo 자체가 서버에서 돌아가는 rpc 함수가 아니잖아. 근데도 서버에서 OnMoveTo의 바디가 돌아갈까?
해답:
OnMoveTo()는 UFUNCTION(BlueprintImplementableEvent)이고, Server RPC가 아닌데도 서버에서 실행될까?Unreal에서는 함수가 Server RPC인지 아닌지보다 “누가 호출했는가”가 훨씬 중요함.
Server_MoveTo()는 Server RPC → 반드시 서버에서 실행됨 (_Implementation() 호출)OnMoveTo()를 호출함 → 이건 단순한 로컬 함수 호출Server_MoveTo_Implementation)가 서버에 있으므로 → OnMoveTo()도 서버에서 실행| 함수 타입 | 호출 주체가 서버일 때 | 호출 주체가 클라이언트일 때 |
|---|---|---|
UFUNCTION(BlueprintImplementableEvent) | ✅ 서버에서 실행됨 | ✅ 클라이언트에서 실행됨 |
UFUNCTION(Server) | ✅ 실행됨 (_Implementation) | ❌ 실행되지 않음 (클라이언트는 서버 RPC 못 실행) |
그래서 OnMoveTo()는 RPC가 아니더라도 "서버에서 호출되었으면 서버에서 실행된다."
UCLASS(Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ABYSSDIVERUNDERWORLD_API UFlyingAIPathfindingBase : public UActorComponent
{
GENERATED_BODY()
public:
UFlyingAIPathfindingBase();
protected:
virtual void BeginPlay() override;
#pragma region Method
public:
UFUNCTION(Server, Reliable)
void Server_MoveTo(FVector TargetLocation);
void Server_MoveTo_Implementation(FVector TargetLocation); // RPC
UFUNCTION(BlueprintNativeEvent)
void MoveTo(FVector TargetLocation);
void MoveTo_Implementation(FVector TargetLocation); // BP fallback
#pragma endregion
};