ESlateVisiblity

  • 위젯을 모니터상의 출력여부에 대한 상태를 제어할 때 사용하는 열거형
  • SetVisibility(ESlateVisibility InVisibility) : 현재 위젯의 상태를 변경할 때
  • GetVisibility() : 현재 위젯의 상태를 확인할 때 (Return ESlateVisibility Visibility)
  • 위젯 애니메이션 블렌딩의 경우
  • 마우스 입력 또는 키보드 입력값을 받을 수 있는지에 대한 여부 결정시

 

 

ESlateVisibility - SlateWrapperTypes.h

/** Is an entity visible? */
UENUM(BlueprintType)
enum class ESlateVisibility : uint8
{
	/** Visible and hit-testable (can interact with cursor). Default value. */
	Visible,
	/** Not visible and takes up no space in the layout (obviously not hit-testable). */
	Collapsed,
	/** Not visible but occupies layout space (obviously not hit-testable). */
	Hidden,
	/** Visible but not hit-testable (cannot interact with cursor) and children in the hierarchy (if any) are also not hit-testable. */
	HitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self & All Children)"),
	/** Visible but not hit-testable (cannot interact with cursor) and doesn't affect hit-testing on children (if any). */
	SelfHitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self Only)")
};

 

  • Visible
    • SetVisibility 설정하지 않을 경우의 기본값
    • 화면에 출력되며 마우스 클릭 및 터치 등의 인터렉션이 가능하다.
    • 일반적으로 위젯이 열려있으며, 버튼, 텍스트 등의 인터렉션이 필요하 경우 (우편함, 로비 플레이 버튼 등)
  • Collapsed
    • 화면에 출력되지 않으며 레이아웃에서 공간을 차지하지 않는 형태
    • 라운드 시작시 상호작용하지 못하는 위젯들 (상점 등)
  • Hidden
    • 화면에 출력되지 않으며 레이아웃에서 공간을 차지하는 형태
    • 플레이어 이름표 애니메이션 처리 또는 레이아웃 위치를 유지해야하는 경우
  • HitTestInvisible
    • 화면에 출력되지만 인터렉션이 불가능하며, Child에게도 적용된다.
    • 화면 전체에 덮인 오버레이의 경우 (대쉬 이펙트, 블러드 이펙트 등)
  • SelfHitTestInvisible
    • 화면에 출력되지만 인터렉션이 불가능한 형태. Child 위젯들에게는 적용되지 않는다.
    • 듀토리얼에서의 특정 버튼의 활성화의 경우

 

ContextSwitching

 

ContextSwitching의 정의

CPU에서 실행할 프로세스 혹은 쓰레드를 다른 프로세스 혹은 쓰레드로 전환하는 방법을 의미합니다.

프로세스에서 쓰레드, 쓰레드에서 프로세스로 전환하는것은 불가능하며 각각의 동일한 구조끼리 실행중인 상태를 전환 하는것을 의미합니다.

 

ContextSwitching을 하는 과정에 대해 알아보기 전에, 몇가지 미리 알아야할 내용을 설명드리겠습니다.

 

 

스케줄러(Scheduler) 

  • 어떤 프로세스나 스레드가 CPU를 사용할지 작업을 결정하는 담당

컨텍스트(Context)

  • CPU가 프로세스나 스레드를 실행하기 위한 모든 정보를 포함 하는것.

오버헤드(OverHead)

  • A라는 행동을 처리할 시 10의 시간이 걸렸는데, 안전성을 고려하여 B라는 처리를 하였을 시 총 20의 시간이 소요되었다. 여기서 증가한 10의 시간을 오버헤드라고 한다.
  • 오버헤드가 점점 누적될 시 시스템이 정지되거나 느려지는 등 심각한 오류가 생길 수 있다.

Process State 

프로세스가 컨텍스트 스위칭을 하기위해 가지는 5가지의 상태가 있습니다..

  • New : 프로세스가 생성되고 시작한다.
  • Running : 프로세스가 동작중인 상태. 프로세스 명령어를 로딩해서 CPU에 옮기고있다.
  • Waiting : Running상태의 프로세스가 동작되는동안 대기중인 상태
  • Ready : 프로세스가 Ready Queue에 들어가서, 차례를 기다리고 있는 상태.
  • Terminated : 모든걸 끝낸 프로세스 상태

PCB(Process Control Block)

  • 컨텍스트 스위칭은 PCB라는 메모리의 공간에 Process 상태값들을 저장하는 블록.
  • 프로세스는 여러개가 실행되는 방식으로 보이지만, TimeSharing을 통해 빠른 속도로 이동하며 프로세스들을 처리해준다.

 

 

ContextSwitching의 전환 과정

예시) 프로세스 P0의 상태값이 Running이다.

  1. 운영체제에서 스케쥴러에 의해 Interrupt 또는 SystemCall이 걸린 상태.
  2. 현재 Running이던 P0의 정보를 OS가 저장한다.
  3. P0의 상태값이 Waiting이 된다. 그 후 Queue구조(FIFO) P1의 상태값이 Running으로 변한다.
  4. 동시에 PCB1 Register에 저장되어있던 값이 P1과 관련된 정보로 변한다.
  5. 이때 CPU에서 실행되던 P0과 관련된 레지스터 값들이 PCB0에 저장된다.
  6. PCB1이 실행된다.

해당 컨텍스트 스위칭을 하는 과정에서 일정한 값의 오버헤드가 발생하며, 실행중인 프로세스가 전환이 됩니다.

 

정리 및 느낀점

정리

컨텍스트 스위칭이란, 프로세스 또는 쓰레드가 각각 다른 프로세스 또는 쓰레드에게 전환화는 것을 말한다.

프로세스는 5개의 상태값을 가질 수 있으며, 컨텍스트 스위칭을 하는 과정에서 상태에 따라 전환을 한다.

PCB는 프로세스의 정보를 저장하는 영역이며, 컨텍스트 스위칭시에 데이터를 옮기거나 저정하기 위해 사용한다.

 

 

 

참고내역 및 출처

https://resilient-923.tistory.com/217

https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4?category=890836

발생한 문제

프로젝트 및 월드 세팅을 언리얼 엔진에서 제공하는 GameState 클래스의 경우 컨트롤러에 빙의한 캐릭터 내
Movement Component가 자동으로 동기화가 됨.

 

게임 내 공통적으로 필요한 기능들을 구현하기 위해 GameStateBase 기반의 커스텀 GS를 생성, 게임모드 생성자에서

GameStateClass = MyGS::StatcClass() 적용, 프로젝트 및 월드세팅 확인 후 결과

다른 컴포넌트들은 정상적으로 동기화가 되었으나, 언리얼에서 제공하는 Movement Component는 동기화가 안됨.

 

해결 과정

AMyGameMode.cpp

AMyGameState::AMyGameState()
{
	bReplicates = true;
	bAlwaysRelevant = true;
	bNetLoadOnClient = true;
}

 

리플리케이티드 및 네트워크 동기화를 위한 변수 true 적용해보기

언리얼에서 제공하는 기본 게임 스테이트 클래스에서는 적용이 되어있었으나,

커스텀 게임 스테이트 클래스에서는 명시적으로 처리해야 하는 것.

  • bReplicates : 클라이언트에 해당 GameState 복제에 대한 여부
  • bAlwaysRelevant : 모든 클라이언트가 항상 리플리케이션 되도록 설정
  • bNetLoadOnClient : 클라이언트가 레벨 로드시 GameState를 생성하도록 설정

 

BP_MyCharacter

 

무브먼트 컴포넌트 내 리플리케이트 설정

  • C++ : GetMovementComponent()->SetIsReplicated(true);

 

두가지의 적용 결과 언리얼에서 제공하는 기본적인 기능들이 리플리케이션이 적용되지 않았습니다.

- Weapon관련 RPC, Health관련 RPC의 경우는 정상적으로 동작됨을 확인

 

 

AGameStateBase -> AGameState 클래스 상속 변경

 

기반 상속구조 변경 후 정상적으로 동기화가 됨.

 

 

멀티플레이 내 GameState VS GameStateBase

  • override 하지 않은 함수들의 경우, 기본적으로 GameStateBase에서 동일한 로직을 구현할 것이라 생각.
  • 생성자 관련 부분 먼저 확인해보기

GameStateBase.cpp - Constructor
GameState.cpp - Constructor

 

  • 생성자 관련 부분에서 State에서는 추가적인 멀티플레이 로직이 없는것을 확인 할 수 있었음.
  • 즉, 생성자 외 오버라이드된 함수 내에서 추가기능을 통해 Possess 관련 동기화과 있을것이라 생각.

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/game-mode-and-game-state-in-unreal-engine

 

공식문서 설명을 보면, 해당 함수 및 변수들이 멀티플레이 관련 역할을 한다고 알 수 있다.

 

// AGameStateBase.cpp
void AGameStateBase::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	UWorld* World = GetWorld();
	World->SetGameState(this);

	FTimerManager& TimerManager = GetWorldTimerManager();
	if (World->IsGameWorld() && GetLocalRole() == ROLE_Authority)
	{
		UpdateServerTimeSeconds();
		if (ServerWorldTimeSecondsUpdateFrequency > 0.f)
		{
			TimerManager.SetTimer(TimerHandle_UpdateServerTimeSeconds, this, &AGameStateBase::UpdateServerTimeSeconds, ServerWorldTimeSecondsUpdateFrequency, true);
		}
	}

	for (TActorIterator<APlayerState> It(World); It; ++It)
	{
		AddPlayerState(*It);
	}
}

// AGameState.cpp
void AGameState::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	FTimerManager& TimerManager = GetWorldTimerManager();
	TimerManager.SetTimer(TimerHandle_DefaultTimer, this, &AGameState::DefaultTimer, GetWorldSettings()->GetEffectiveTimeDilation() / GetWorldSettings()->DemoPlayTimeDilation, true);
}

 

  • 주요 문제는 StateBase 상속 시 Component가 동기화 되지않음
  • 즉, Component 관련 설정이 문제다. -> PlayerArray에 추가하는 로직이 오버라이드 되어있다.
  • 언리얼은 서버 동기화시 실시간성을 동시 지원하기위해 예측 및 Reconciliation 방법을 사용.
  • 동기화시 서버 월드와 클라이언트의 월드는 서로 다르기때문에 월드 서버를 기준으로 동작해야된다.
    • TimeManager를 통해 서버의 월드를 Simulate해서 클라이언트의 월드를 복제, 시간값 관련 동기화

 

 

 

 

+ Recent posts