This document is about: QUANTUM 2
SWITCH TO

목적 지향적 행동 계획 (베타)


Available in the Gaming Circle and Industries Circle
Circle

1. 소개

GOAP Quantum 코드와 Visual Editor는 모두 베타 단계입니다.

1.1 GOAP은 무엇인가요?

목표 지향 행동 계획(GOAP)은 두 부분으로 구성된 AI 기술입니다:

  1. 현재 상황에서 지정된 목표 집합에서 가장 적합한 목표 선택. 목표(욕망이라고도 함)는 다음과 같은 것이 될 수 있습니다: 대상을 물리치기, 치유하기, 적기를 훔치기, 도주(적으로부터)
  2. 이 목표를 충족하는 지정된 작업 풀에서 작업 집합(계획) 찾기. 액션은 객체 찾기, 대상 찾기, 픽업 객체(예: 총, 적기, 체력 팩)일 수 있습니다 위치로 이동, 전투장으로 이동, 사격

1.2 BotSDK AI 접근법과 비교

FSM, HFSM 및 행동 트리와 같은 보다 표준적인 AI 접근 방식과는 달리, 설계자에 의해 생성되는 정확한 AI 동작은 없습니다. AI 에이전트는 현재 상황(세계 상태)을 기반으로 런타임에 어떤 니즈가 있는지, 무엇을 할 수 있는지, 정확한 단계는 계획되어 있는지를 알려줍니다.

강점

  • 복잡성을 잘 처리합니다 이전 AI 동작에서 자동으로 작동하는 새로운 목표와 액션을 추가하는 것은 간단합니다.

  • 대규모 프로젝트의 개발 시간을 단축할 수 있습니다. 충분한 규모의 작업 및 목표 세트가 생성되면 다양한 동작을 가진 많은 AI 에이전트에 재사용할 수 있습니다

  • 자연스러운(흐림) 행동 AI 행동이 특별하지 않으면 플레이어는 원하지 않으면 일부 패턴을 발견하기가 더 어렵습니다. 일부 유틸리티/관련성/비용을 계산하는 모든 AI와 마찬가지로, AI가 유사한 상황에서 약간 다르게 작용할 가능성이 높다는 많은 가치가 고려되고 있습니다.

  • 유일한 솔루션

    많은 가능한 조치를 통해 AI는 고유한 해결책을 찾을 수 있는 문제를 해결하는 방법에 대한 많은 가능성을 가지고 있습니다. 이러한 행동은 좋고 나쁨을 모두 나타낼 수 있습니다. 반면에 너무 많은 행동을 하는 것은 계획 수행에 영향을 미칠 수 있으므로 신중하게 접근할 필요가 있습니다.

단점

  • 계획 파트(적절한 일련의 조치를 찾는 프로세스)는 많은 가능성을 평가해야 하므로 GOAP는 일반적으로 더 가벼운 AI 솔루션(예: FSM)보다 느릴 수 있습니다

  • 숙련하기에는 좀 더 복잡함 GOAP AI를 설계할 때 사용자는 복잡한 세계를 월드 상태 값으로 단순화하는 방법을 파악한 다음 항상 행동을 직접 지정하기보다는 GOAP 조치가 이 월드 상태에 어떤 영향을 미칠지에 대해 생각해야 합니다.

  • AI가 구체적으로 무엇을 해야 하는지 지시받지 않기 때문에 보스 싸움과 같은 “스크립트화된” AI 행동을 하는 것은 번거롭습니다

GOAP의 장점을 가장 잘 활용하기 위해서는 행동과 목표를 신중하게 설계해야 합니다. GOAP 조치는 원자적이어야 합니다. 즉, 이렇게 새로 생성된 조치가 주변의 다른 조치와 함께 다른 상황에서 행동할 수 있는 경우에만 더 복잡한 조치를 여러 조치로 분할해야 합니다. 예를 들어 FindNest , GoToCombatRangeAttack 액션으로 나눌 수 있는 일부 복잡한 KillEnemyNest 액션을 들 수 있습니다. 만약 그러한 접근법이 가능하지 않거나 바람직하지 않다면, 아마도 더 표준적인 AI 솔루션을 당장 사용하는 것이 더 나을 것입니다.

2. Quantum GOAP 코딩

2.1 구현

먼저 코드 관점에서 GOAP를 분석하여 몇 가지 이미지 예제를 사용하여 내부적으로 어떻게 작동하는지 이해해 보겠습니다. 그럼 유니티 에디터에서 직접 분석하여 따라해보겠습니다.

GOAP의 핵심은 GOAPManager 에 있습니다. 관리자(GOAP의 맥락에서 planner 라고 함)는 최상의 목표를 선택하고, 선택한 목표를 달성하는 계획(행동 순서)을 수립하며, 가능하면 계획에서 모든 행동을 실행합니다.

가능한 일련의 작업 검색은 월드 상태 차이(목표 상태와 다른 월드 상태 플래그 수)인 휴리스틱을 사용하여 후진 A* 를 통해 수행됩니다.

BotSDK GOAP는 매우 빠르고 가볍지만 특정 게임 요구에 따라 더욱 확장할 수 있습니다.

2.2 GOAP 에이전트 생성하고 업데이트하기

다음은 자체 에이전트를 만들고 업데이트하기 위해 수행해야 하는 작업을 단계별로 보여 줍니다:

  1. 엔티티에 GOAPAgent 컴포넌트를 추가합니다. 유니티에서 엔티티 프로토타입 상에서 바로 수행할 수 있지만, 프레임 API를 사용하여 Quantum 코드내에서 직접 수행할 수 도 있습니다.

  2. 원하는 GOAPRoot 에셋을 찾고 초기화 메소드 상에서 사용합니다:

    C#

    var goapRoot = frame.FindAsset<GOAPRoot>(playerData.GOAPRoot.Id);
    GOAPManager.Initialize(frame, entity, goapRoot);
    
  3. 파라미터로 에이전트 엔티티를 전달하여 Update 메소드를 호출합니다:

    C#

    GOAPManager.Update(frame, filter.Entity, frame.DeltaTime);
    
  4. 필요시, 에이전트의 현재 상태를 수동으로 설정합니다:

    C#

    goapAgent->CurrentState.SetFlag();
    

2.3 GOAP 상태

world state

GOAP 상태는 플래너와 관련 된 게임 상태를 나타냅니다. 각 AI 에이전트는 고유한 GOAP 상태를 가집니다. 구현에서 상태는 PositiveNegative 비트마스크로 표시됩니다. 즉, 각 월드 상태 플래그는 true, false 및 non-defined의 세 가지 값을 가질 수 있습니다.

올바른 플래그 세트를 선택하는 것은 좋은 GOAP AI 설계를 위해 매우 중요합니다. 일반적인 규칙은 플래그가 계획 중에 변경될 수 있는 경우에만 플래그가 월드 상태에 있어야 한다는 것입니다. (=는 일부 GOAP 조치의 Condition 또는 Effect 로 사용됩니다).

예: 다른 게임 코드에서 IsHungry를 조건이나 효과로 사용하는 GOAP 액션이 없다면 IsHungry 플래그를 세계 상태에 두는 것은 의미가 없습니다. 그런 경우에는 고객사의 데이터에 IsHungry 플래그를 지정하는 것이 좋습니다.

월드 상태에 플래그를 추가하려면 GOAPState.qtn 파일에서 EWorldState enum을 편집해야 합니다.

사용자 지정 데이터로 세계 상태를 확장할 수 있습니다.

2.4 GOAP 목적

goal sample

대상 상태 계획 프로세스 중에 플래너가 도달하려고 시도하는 것을 명시합니다.

상태 시작 일반적으로 비워 둡니다. 플래너가 계획 프로세스를 시작할 때 현재 에이전트의 상태를 가져와 목표의 Start State 와 병합합니다. 그러면 이 병합된 상태는 FROM 상태로 작동하고 Target State 는 TO 상태로 작동합니다.

노트: 일반적으로 특정 작업을 계획하기 위해 에이전트 상태에서 일부 플래그를 지우는 데 사용됩니다.

확인 목표가 유효하지 않으면 목표 선정 과정에서 고려되지 않습니다.

관련성 이 목표가 얼마나 관련성이 있는지 설명합니다. 관련성이 가장 큰 목표는 기획자가 선정합니다. 두 개의 유효한 목표가 동일한 관련성을 가질 경우 목표 목록에서 첫 번째 목표가 선택됩니다.

비활성 시간 목표를 재사용하는 데 걸리는 시간입니다.

노트: 비활성화 시간은 AI 에이전트가 동일한 목표를 여러 번 연속으로 실행하는 것이 상황에 가장 적합한 목표로 간주되는 경우에도 종종 사용됩니다(예: 적이 5개의 수류탄을 연속으로 던지는 것을 원하지 않을 수 있습니다). 또한 계획을 찾을 수 없는 상황(현재 상황에서는 일부 조치가 유효하지 않음)과 다른 목표가 선택되어야할 때 중요합니다.

IsFinished 목표가 충족되면 계획자는 이 목표를 비활성화하고 새로운 목표를 찾기 시작합니다. 목표는 IsFinished 가 참이거나 에이전트의 GOAP 상태에 목표의 Target State 가 포함된 경우 충족됩니다.

중단 동작 활성 목표(계획)의 실행이 중단될 수 있습니다. 중단이 활성화된 경우 계획자는 더 관련성이 높은 목표가 있는지 주기적으로 확인합니다. 그렇다면 현재 계획의 실행이 중지되고 새로운 목표가 계획됩니다.

Unknown

● 항상 - 더 적절한 목표가 존재하는제 항상 확인합니다
● 없음 - 플랜은 절대로 중단되지 않습니다
● 액션 기반 - 플랜이 중단된 경우 활성 액션이 제어됩니다.

OnInitPlanning 계획 프로세스가 시작되기 전에 실행되는 작업입니다.

OnActivate 계획이 성공적으로 발견되고 계획 실행이 시작될 때 실행되는 작업입니다.

OnDeactivate 목표가 비활성화될 때 실행되는 작업입니다.

2.5 GOAP 액션

action sample

조건 계획에서 이 작업을 고려하기 위해 필요한 상태입니다.

효과 에이전트의 상태에 이 액션의 효과

확인 유효하지 않은 작업은 계획 프로세스 중에 고려되지 않습니다.

노트: 이렇게 하면 불필요한 플래그로 세계 상태를 복잡하게 만들지 않고 특정 상황에서 특정 작업을 “비활성화”할 수 있습니다. 월드 상태 섹션에서 언급했듯이 월드 상태는 계획 프로세스 자체에서 변경될 수 있는 속성만 포함해야 합니다.

비용 작업 비용을 결정합니다. 이 계획자는 총 비용이 가장 낮은 일련의 작업을 찾으려고 합니다. 작업 비용은 0보다 커야 합니다. 일반적으로 비용은 조치가 소요되는 시간(초)으로 생각하는 것이 가장 좋으나, 어느 정도의 합리적인 범위(예: 0.5 ~ 5, 대부분의 조치는 1)를 유지합니다. 비용 차이가 너무 크면 GOAP 성능이 저하될 수 있습니다. 자세한 내용은 최적화 섹션을 참조하십시오.

IsDone 작업이 완료되면 계획자는 계획의 다음 작업을 계속합니다. IsDone 이 true인 경우 또는 모든 Effects 가 에이전트 상태에 있을 때 자동으로 작업이 완료됩니다.

IsFailed 작업이 실패하면 전체 계획이 실패하고 새로운 최상의 목표에 대한 검색이 다시 시작됩니다.

Interruptible 작업을 중단할 수 있는지 여부입니다. 이 설정을 고려하려면 현재 활성 목표에서 Interruption BehaviourBased On Actions 으로 설정해야 합니다.

OnActivate 이 GOAP 동작이 활성화되면 AI 동작이 실행됩니다.

OnUpdate 이 GOAP 작업이 업데이트될 때 실행되는 AI 작업입니다.

OnDeactivate 이 GOAP 동작이 비활성화될 때 실행되는 AI 작업입니다.

계획 상태 확인 계획 상태 검증 노드는 고급 GOAP 기능에 사용됩니다. 기본적으로 현재 계획 상태를 기준으로 계획 중에 조치를 검증한다는 의미입니다. 또한 계획을 분기할 수도 있습니다.

3. 에디터

3.1 새로운 GOAP 생성하기

create document

편집기의 상단 막대에서 (+) 버튼을 클릭한 다음 대체 GOAP을 선택합니다.

그런 다음 HFSM 파일을 저장하라는 메시지가 표시됩니다. 원하는 곳에 저장합니다. 이렇게 하면 Visual 편집기에서 완료한 작업을 저장하는 데 사용되는 데이터 에셋이 생성됩니다:**

goap asset

노트: 지금 선택하는 이름은 시각적 편집기에서 수행한 작업을 컴파일할 때 추가로 생성되는 다른 데이터 에셋의 이름이 됩니다. 실제로 봇을 구동하는 데 사용되는 데이터 에셋이 될 것이므로 이미 추천하는 이름을 선택할 수 있습니다.

파일을 저장하면 기본 Bot SDK 창에 GOAP 문서의 가장 기본적인 형식이 표시되며 하나는 GOAP Goals이고 다른 하나는 GOAP Actions이라는 두 개의 컨테이너가 표시됩니다.

goap clean document

3.2 새로운 GOAP 목표 생성하기

새 목표를 만들려면 Bot SDK 창에서 빈 공간을 마우스 오른쪽 버튼으로 클릭하고 GOAPDefaultGoal을 선택합니다. 고급 설정에서는 오른쪽 클릭 메뉴에도 나열되는 목표를 직접 만들 수 있습니다.

create goal

루트 레벨에서, 수정하지 않은 목표 노드는 다음과 같습니다:

goal root level

목표 노드를 두 번 클릭하여 세부 정보를 볼 수도 있습니다. 기본 목표는 AI에 대해 원하는 것을 표현하기 위해 충족해야 하는 많은 필드를 제공합니다.

goal detailed

모든 목표의 두 가지 핵심 개념은 “Start State”와 “Target State”인데, 이는 특정 GOAP 에이전트가 주어지면 현재 세계 상태를 나타내는 EWorldState 타입의 열거형입니다(따라서 공유/글로벌 상태가 아님). 이러한 상태는 에이전트의 목표를 충족하는 방식으로 게임 상태를 변경할 목표를 선택하기 위해 계획 프로세스에서 사용됩니다.

월드 상태 플래그를 포지티브 또는 네거티브로 표현할 수 있습니다. 계획 과정에서 계획자는 원하는 세계 상태를 적절하게 충족하는 목표를 필터링합니다. 예를 들어 이것을 조금 예로 들어 보겠습니다.

노트: Quantum GOAP Coding 섹션에서 월드 상태의 정의에 대한 자세한 내용을 확인할 수 있습니다.

3.2.1 시작/목표 상태 설정하기:

  1. Start State 또는 Target State 버튼을 클릭하여 계획 프로세스 중에 반드시 월드 상태가 포함해야 하는 플래그를 부정 또는 긍정으로 정의합니다;

    add world flag
  2. 원하는 상태를 선택하면 목표 노드 내에 포함됩니다:

    world states added
  3. 기본적으로 월드 상태는 작은 녹색 원과 함께 나타납니다. 즉, 월드 상태 플래그에 월드 상태 플래그 그리고 긍정이여야 한다는 것이 포함될 것으로 예상됩니다. 그러면 작은 녹색 원을 클릭하여 부정으로 변경할 수 있습니다. 그러면 원이 빨간색으로 표시됩니다:

    world state negative
  4. 위의 샘플에서 월드 상태 플래그는 이 목표를 계획 프로세스에 포함하기 위해 에이전트가 근접 범위에 있지만 복구 중이 아님을 알려주는 것으로 예상됩니다(다른 목표와 함께). 그러나 대상 상태의 결과가 에이전트의 현재 목표에 기여하는 경우에만 포함됩니다. 위의 예에서, 목표를 선택한 결과는 목표를 패배시키는 것입니다;

  5. “Root” 수준에서 월드 상태 플래그를 보고 변경할 수도 있습니다. “ESC”를 누르거나 상단 바에 있는 브레드스크럼에 있는 “Root” 버튼을 클릭하여 루트로 돌아갈 수 있습니다. 루트 수준 목표는 항상 요약된 다음과 같습니다:

    root level world flags

3.2.2 목표 포함과 구성하기

계획 프로세스에 목표 노드를 포함하려면 목표 노드를 GOAP 목표 컨테이너(회색 영역)에 포함해야 합니다. 이를 위해 목표 노드를 컨테이너 내부로 끌어다 놓기만 하면 됩니다::

goals container

목표 노드 이름 변경도 가능합니다. 이렇게 하려면 노드를 선택하고 F2를 누르거나 노드를 마우스 오른쪽 버튼으로 클릭한 후 다른 “이름 바꾸기”를 선택합니다:

goal renamed

여기서 주목해야 할 한 가지 중요한 점은 노드의 순서가 중요하다는 것입니다. 최상위 노드는 다른 노드에 비해 우선 순위가 높습니다. 플래너가 동일한 관련성을 가진 둘 이상의 목표를 에이전트의 목표를 달성하는 데 동일한 방식으로 사용할 수 있다고 결정한 경우 노드 포지셔닝은 타이브레이커입니다. 목표 노드의 이름을 변경하고 올바른 순서로 정렬하는 것이 좋습니다:

organised goals

3.3 새로운 GOAP 액션 생성하기

노드 생성, 편집 및 구성과 관련하여 위와 동일한 개념이 GOAP 액션에 적용됩니다. 다음은 작업 컨테이너에 포함된 몇 가지 작업의 간단한 예제입니다:

actions container

3.4 목표/작업 무시 및 뮤트

노드를 삭제할 필요 없이 계획 프로세스에서 목표와 액션을 취할 수 있습니다. 노드 데이터를 다시 추가하기로 결정한 경우 노드 데이터를 손실하지 않고 대체 경로를 디버깅하고 시도할 때 유용합니다. 이를 위한 두 가지 주요 방법이 있습니다:

  1. 노드를 무시하기 위해 , 더 이상 무시하지 않으려면 컨테이너에서 제거한 후 다시 추가하세요.
  2. 노드를 뮤트하기 위해 , 마우스 오른쪽 버튼을 클릭하고 다른 “Mute”를 선택합니다. 그러면 노드가 뮤트 상태임을 나타내기 위해 약간 투명해집니다. 컨테이너에서 노드의 위치/순서를 잃지 않으므로 노드를 뮤트하는 데 유용합니다.

무시되거나 뮤트된 노드는 컴파일 프로세스 중에 건너뜁니다. 따라서 컴파일을 다시 수행하는 것을 잊지 마십시오.

3.5 슬롯값 설정하기

GOAP 목표 및 GOAP 작업을 편집할 때(두 번 클릭한 후) 많은 슬롯 값을 편집할 수 있습니다. 일부는 하드 코딩된 값이거나 다른 노드에서 가져온 값일 수 있으며, 일부 슬롯(예: 작업 슬롯)은 하나 이상의 작업 노드에만 연결할 수 있습니다.

이 섹션에서는 이러한 값을 정의하는 방법에 대한 몇 가지 대안을 살펴봅니다.

3.5.1 원시 타입

예를 들어, GOAP 목표에는 FP와 Boolean 유형의 슬롯이 몇 개 있습니다. 다음 슬롯 값을 클릭하여 편집기에서 직접 정의할 수 있습니다:

edit slot

그러나 하드 코딩 값 외에도 미리 정의된 값을 포함할 수 있는 노드 또는 해당 슬롯 값을 폴링할 때 실행될 미리 정의된 로직과 슬롯을 연결할 수도 있습니다. 이렇게 하는 방법은 여러 가지가 있으며, 이 주제에서 모든 방법을 설명합니다:

공유 개념.

3.5.2 액션 슬롯

GOAP 목표와 GOAP 액션은 모두 오른쪽에 액션 슬롯이 있습니다. 이것들은 사용자들에 의해 구현될 것이고, 실제로 게임 상태를 변화시킬 것입니다. 이러한 작업을 사용하여 대상을 추적하거나 공격을 수행하거나 항목을 수집할 수 있습니다.

중요: “GOAP Action”과 “Action”을 혼동하지 마십시오. 이것들은 두 가지 다른 개념입니다.

linked action

액션은 Bot SDK의 HFSM 및 UT에서도 재사용되기 때문에 일반적인 주제입니다. 이 항목의 작업 사용 방법에 대한 자세한 내용은 다음을 참조하십시오:

액션 코딩하기

3.5 GOAP 컴파일

작성된 GOAP를 실제로 사용하기 위해서는 작업 내용을 컴파일 해야만 Quantum 시뮬레이션에서 사용되는 Quantum 에셋을 얻을 수 있습니다. 컴파일에는 두 가지 옵션이 있습니다:

compile buttons
  • 왼쪽 버튼은 현재 열려 있는 문서만 컴파일하는 데 사용됩니다.
  • 오른쪽 버튼은 프로젝트에 있는 모든 AI 문서를 컴파일하는 데 사용됩니다.

GOAP 파일 위치: Assets/Resources/DB/CircuitExport/GOAP_Assets.

3.6 봇에서 사용할 AI 설정

컴파일된 에셋을 사용하려면 Quantum 코드 내에서 참조해야 합니다. GUID를 기반으로 자산을 로드하거나 AssetRefGOAPRoot를 생성하여 원하는 AI 에셋을 가리킬 수 있습니다. 일부 컴포넌트, 코드 아키텍처에 더 적절한 데이터 에셋, RuntimeConfig, RuntimePlayer에 포함될 수 있습니다

goap root reference

PS: Quantum GOAP Coding 섹션에서 자세한 내용을 확인하세요.

4. 최적화와 디버깅

4.1 디버깅

BotSDK에는 자체 디버깅 툴이 제공되지만 현재 GOAP 편집기에서는 이 툴을 사용하지 않습니다. 디버거를 추가하는 것은 GOAP 편집기의 다음 기능 중 하나입니다.

당분간은 GOAP 로깅 기능을 사용할 수 있습니다. 엔티티를 GameManager.DebugEntity에 할당하기만 하면 되고 디버그 메시지가 콘솔에 인쇄됩니다.

goap debug 1

4.2 최적화

GOAP 최적화는 일반적으로 A* 가 처리해야 하는 노드 수를 제한하는 것으로 귀결됩니다. 처리에 소요된 수와 시간을 확인하려면 엔티티 디버깅을 사용하도록 설정하고(위 참조) 로그 메시지를 확인합니다:

goap debug 2

노트: 검색 시간 값은 일반적으로 게임의 실제 빌드보다 유니티 편집기에서 훨씬 오래걸립니다. 하지만 성능을 향상시키기 위해 노력할 때 좋은 참고 자료가 됩니다.

일반적으로 방문한 노드의 수를 낮게 유지하기를 원하지만 정확한 수는 AI의 복잡성에 따라 다릅니다. 방문한 노드 수가 너무 많은 경우(예: 단순 AI의 경우 100개 이상), 액션이 잘못 설계되었을 가능성이 있습니다. 일반적인 문제는 행동의 조건과 효과가 너무 모호해서 기획자가 많은 옵션을 고려하고 있지만 대부분은 유효하지 않다는 것입니다. 또 하나 주목해야 할 것은 액션 비용 입니다. A* 는 비용을 사용하여 계획 프로세스 중에 가장 적합한 작업 순서를 결정합니다. 따라서 작업 비용을 잘못 설정하면 플래너가 올바른 지점으로 돌아가기 전에 많은 막다른 골목에 부딪힐 수 있습니다. 가장 좋은 방법은 비용을 초 단위의 시간으로 상상하되, 조치 간에 비용 차이가 크지 않도록 현실적으로 덜 걸리거나 그 이상이 소요되는 경우에도 일정 범위(예: 0.5 - 5, 대부분의 조치는 1)로 유지하는 것입니다.

5 추가 내용

5.1 AIParam

직접 설정하거나 Blackboard/Constant/Config Nodes 에서 설정하는 등 다양한 방법으로 정의할 수 있는 보다 유연한 필드를 원하는 경우 유용한 AIParam 사용에 대한 자세한 내용은 여기에서 확인하십시오

5.2 AIContext

에이전트 상황별 정보를 매개 변수로 전달하는 방법에 대한 자세한 내용은 여기에서 확인하십시오: AIContext.

5.3 BotSDKSystem

Blackboard 메모리 할당 해제와 같은 일부 프로세스를 자동화하는 데 사용되는 클래스가 있습니다. 자세한 내용은 여기를 참조하십시오: BotSDKSystem.

5.4 Visual Editor 주석

Visual Editor에서 주석을 작성하는 방법에 대한 자세한 내용은 여기에서 확인하십시오: Visual Editor 주석.

5.5 컴파일 내보내기 폴더 변경

기본적으로 Bot SDK의 컴파일로 생성된 에셋은 Assets/Resources/DB/CircuitExport 폴더에 배치됩니다. 내보내기 폴더를 변경하는 방법은 여기를 참고하세요: 내보내기 폴더 변경하기.

Back to top