최종 프로젝트 - AI Enemy 구현(2)

정혜창·2025년 5월 9일

내일배움캠프

목록 보기
53/64

MoveTo_Implementation()이 꼭 필요할까?

✔ Unreal이 BlueprintNativeEvent를 호출하는 방식:

  1. UFUNCTION(BlueprintNativeEvent)로 정의된 함수는 내부적으로 ProcessEvent() 호출을 사용함
  2. ProcessEvent()는 다음을 판단함:
    • 이 클래스 또는 상속 계층에 해당 함수가 Blueprint에서 오버라이드되었는지?
    • → 되어 있다면: BP 바디 실행
    • → 안 되어 있다면: MoveTo_Implementation() 실행

✅ 즉, BP override가 없을 경우를 대비해 반드시 _Implementation()이 있어야 함.

없으면 링크 에러(LNK2019 등) 발생.

❗ 그렇다면 BlueprintImplementableEvent는 왜 안 될까?

🔥 핵심 차이점: 호출 경로에 ProcessEvent()가 없음

UFUNCTION(BlueprintImplementableEvent)
void MoveTo(FVector TargetLocation);
  • 이 함수는 C++에서 직접 호출해도 아무 바디가 없음
  • Unreal은 이 함수를 BP에서만 호출하도록 의도했기 때문에, MoveTo()를 호출해도 ProcessEvent 경유로 BP 바디를 실행하지 않음

✅ Q2. 왜 BlueprintImplementableEvent는 서버 RPC가 안 되는가?

🔥 핵심 이유:

BlueprintImplementableEvent는 Unreal이 리플렉션을 통해 C++ 호출 경로를 만들지 않기 때문입니다.

자세히 말하면:

  • BlueprintImplementableEventC++에 구현이 전혀 없음
  • Unreal이 그 함수를 BP에서만 호출한다고 가정하고 컴파일합니다
  • ProcessEvent를 호출하지 않음 → 서버/클라이언트 분기 처리도 안 됨
    • ProcessEvent()가 서버/클라이언트 분기 처리도 하느냐?
      • ✅ 맞음. Unreal의 ProcessEvent()는 네트워크 RPC 처리를 포함.
  • 따라서 UFUNCTION(Server, Reliable, BlueprintImplementableEvent) 같이 쓰면:
// 이런 거
UFUNCTION(Server, Reliable, BlueprintImplementableEvent)
void Foo();
  • → 컴파일은 됨
  • 실행 시 아무 일도 일어나지 않음 (RPC 호출은 일어나지만 구현이 없어서 아무것도 실행 안 됨)

📌 흐름 요약:

Unreal의 UObject::ProcessEvent(UFunction*, void* Params)는 단순히 함수를 실행하는 게 아님.

이 함수는 다음을 수행

  1. UFunction에 등록된 메타 정보 확인 (FunctionFlags)
    • 예: FUNC_Net, FUNC_NetServer, FUNC_BlueprintCallable, etc.
  2. NetDriver가 있고 RPC 조건이 맞는지 검사
    • 이 함수가 RPC이고, 현재 Role이 맞는지 확인 (Role == ROLE_Authority, etc.)
  3. 조건이 맞으면:
    • 클라이언트 → 서버 또는 서버 → 클라이언트로 RPC 패킷 전송
    • 아니면 그냥 로컬 실행

✅ 이 덕분에 Server, Reliable, BlueprintNativeEvent 함수는

C++에서 MoveTo() 한 줄만 호출해도 BP 바디가 서버에서 실행.

Unreal이 내부적으로 알아서 ProcessEvent() 경유로 네트워크 호출까지 처리.

📌 핵심 정리

BlueprintNativeEvent

  • C++에서 MoveTo() 호출 → ProcessEvent 호출됨
  • BP에서 오버라이드 있으면 그 바디 실행됨
  • 오버라이드 없으면 → C++의 MoveTo_Implementation() 실행됨
  • 그래서 _Implementation()필수

BlueprintImplementableEvent

  • C++에서 MoveTo() 호출 시 → 바디가 전혀 없음
  • Unreal은 BP에서만 호출할 것이라고 가정 → ProcessEvent도 안 씀
  • C++에서 호출해도 아무 효과 없음 (BP 함수처럼 생겼지만 전혀 기능 안 함)

따라서 어제 구상한 것과 다르게 BlueprintNativeEvent를 써야함.

✅ 2. 그럼 왜 virtual을 안 쓰는가? (BlueprintNativeEvent인데도)

이건 언리얼 리플렉션 시스템의 설계상 이유입니다.

📌 일반 C++에서라면?

cpp
복사편집
class A {
public:
    virtual void Foo(); // 다형성 위해 필요
};

이건 컴파일 타임에 vtable 기반으로 연결되죠.


📌 하지만 Unreal에서는?

cpp
복사편집
UFUNCTION(BlueprintNativeEvent)
void MoveTo(FVector TargetLocation);
  • Unreal은 UFunction 메타 정보를 통해 해당 함수가 BP에서 오버라이드 되었는지, 아니면 _Implementation()을 써야 하는지를 판단합니다.
  • 그리고 MoveTo()는 실제 호출 시, virtual을 안 써도 ProcessEvent()를 통해 다형성이 실현됩니다.
  • 이 다형성은 런타임 동적 디스패치 방식이고, C++의 vtable과는 다릅니다.

🔥 핵심 이유: Unreal의 리플렉션 시스템은 virtual 키워드 없이도 오버라이드 가능하게 설계되어 있음

즉:

일반 C++ 다형성Unreal 방식
virtualvtable 기반UFUNCTIONUFunction + ProcessEvent 기반
컴파일 타임 디스패치런타임 디스패치 (ProcessEvent)
virtual 필수virtual 불필요, 오히려 붙이면 헷갈릴 수 있음

그래서 BlueprintNativeEvent로 바꾸고 virtual 삭제함

근데도 안됌.

왜 안될까?

❗ 이유: BlueprintNativeEventServer(RPC)는 동시에 쓰면 특별한 조건이 필요합니다

Unreal은 다음과 같이 분리된 구조를 강제:

✅ 올바른 방식 (서버 RPC + 블루프린트 구현)

  1. BlueprintNativeEvent → BP 오버라이드 가능
  2. 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 리플렉션 시스템에서 모호함을 유발

🔧 해결책: RPC 역할과 BP 역할을 분리

👉 방법 1. RPC는 C++로 처리하고, 내부에서 BP 이벤트 호출

// 헤더
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 함수 호출
}

가장 안정적인 구조

  • RPC → Server에서 실행됨
  • OnMoveTo() → BP에서 자유롭게 이동 처리 구현 가능

근데 OnMoveTo 자체가 서버에서 돌아가는 rpc 함수가 아니잖아. 근데도 서버에서 OnMoveTo의 바디가 돌아갈까?

해답:

✅ Q: OnMoveTo()UFUNCTION(BlueprintImplementableEvent)이고, Server RPC가 아닌데도 서버에서 실행될까?

▶️ A: “Yes", 호출한 쪽이 서버라면 서버에서 실행됨.


🔍 왜 그런가?

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
		
};
profile
Unreal 1기

0개의 댓글