기존 콘텐츠 덮어쓰기 및 수정
기본 게임 또는 다른 모드의 콘텐츠를 덮어쓰거나 수정하는 것이 가능합니다. 자신의 콘텐츠를 생성하여 확장하는 것보다 권장되지 않으며, 같은 것을 덮어쓰는 모드들은 서로 호환되지 않을 가능성이 높기 때문입니다. 하지만 특정 기능을 달성하는 가장 실용적인 방법입니다.
라이브러리 모드 사용하기
다른 모더들이 이미 콘텐츠를 덮어쓰거나 수정하는 과정을 돕는 모드를 만들었습니다. 이들은 많은 시간을 절약할 수 있습니다.
TweakIt
Feyko의 TweakIt은 게임 콘텐츠를 프로그래밍적으로 수정하기 위해 Lua 스크립트를 작성할 수 있게 해줍니다.
문서는 이 사이트의 사이드바에 있는 '문서 전환기’를 통해 찾을 수 있으며, 여기에서 확인할 수 있습니다.
이 모드는 공식적으로 출시되지 않았지만, TweakIt 디스코드에서 초기 빌드를 다운로드할 수 있으며, 소스 코드는 여기에서 찾을 수 있습니다.
ContentLib
ContentLib는 Nog와 Robb이 만든 모드로, JSON 파일을 작성하여 콘텐츠를 생성하고 수정할 수 있게 해줍니다. 또한 런타임에 콘텐츠를 프로그래밍적으로 생성, 수정 또는 구문 분석할 수 있는 블루프린트 및 C++ API를 제공합니다. 추가로 JSON 파일을 통해 CDO 수정의 제한된 형태를 제공합니다(아래 설명).
문서에는 일반적인 작업에 대한 단계별 안내가 포함되어 있으며, 여기에서 확인할 수 있습니다.
이 모드는 공식적으로 출시되었으며, 문서에는 모드가 이를 의존하도록 구성하는 방법이 설명되어 있습니다.
CDO 조작 사용하기
라이브러리를 사용하지 않고 콘텐츠를 덮어쓰고 싶다면, 올바른 메커니즘은 클래스 기본 오브젝트(CDO) 조작입니다. 때때로 CDO 수정이라고도 불립니다.
CDO 수정을 수행하려면, 덮어쓰려는 클래스의 클래스 기본 객체를 가져와 관련 속성을 변경합니다.
CDO에 대한 변경 사항은 수정 후 생성된 선택된 클래스의 모든 객체에 반영됩니다. 이것을 사용할 때는 주의해야 하며, 다른 모드와 기본 콘텐츠를 흔적 없이 망가뜨릴 수 있습니다. 안전상의 이유로, 이 기능은 모드에 속하지 않은 클래스를 수정하려고 할 때 경고를 기록합니다.
CDO를 수행할 때, 실제로 기존 객체에서 아무것도 변경하지 않고 "아키타입" 객체의 속성 값만 덮어쓰고 있습니다. 기존 클래스의 모든 인스턴스를 가져와서 값을 수정해야 할 수도 있습니다. 이렇게 하면 새로운 원하는 값과 일치하도록 보장할 수 있습니다. 모드 로딩 과정에서 CDO 수정을 더 일찍 수행하면 이 추가 단계를 제거할 수 있습니다.
CDO 조작을 수행할 때는 언리얼이 패치된 객체(및 그 자손)를 가비지 수집하지 않도록 CDO를 메모리에 유지해야 합니다. 이를 위해 속성에서 CDO를 참조해야 합니다. 아래의 언어별 섹션에서 더 많은 정보를 확인할 수 있습니다.
CDO의 한계 이해하기
클래스 기본 오브젝트 수정을 이해하는 것은 모든 것을 달성할 수 있는 것은 아닙니다.
CDO 수정은 이미 객체에 존재하는 동작과 속성에만 영향을 미칠 수 있으며, 새로운 동작을 정의할 수는 없습니다.
또한 일부 기능이 내부적으로 구현되는 방식 때문에 클래스 기본 객체를 수정해도 전혀 효과가 없을 수 있습니다. 변경한 값이 다른 것에 의해 덮어쓰여질 수 있기 때문입니다.
블루프린트
블루프린트에서 Get Class Default Object
노드를 사용하여 클래스 기본 객체를 가져올 수 있습니다.
그 후, 클래스의 기존 세터를 사용하여 필드를 수정할 수 있습니다.
필드를 변경하려면 접근 변환기를 사용해야 할 수도 있습니다.
CDO에 대한 참조를 유지하려면, CDO를 변경하는 블루프린트에서 오브젝트 유형의 속성을 생성합니다. 속성의 값을 CDO로 설정한 후 객체를 조작합니다. 여러 CDO를 수정하는 경우, 속성을 대신 객체 배열로 만들고 각 CDO를 배열에 추가할 수 있습니다.
ExampleMod의 SubGameWorld_ExampleMod_SchematicCdoEdit
에서 코드 예제를 확인하십시오.
C++ 예제
다음은 Kyrium의 KBFL에서 압축기 및 그 추출기 노드에 추가 허용 클래스를 추가하는 예제입니다.
void UKBFLResourceNodeDescriptor_ResourceWell::AfterSpawning()
{
if(const TSubclassOf<AFGBuildableFrackingActivator> BPBuildableFrackingActivator = LoadClass<AFGBuildableFrackingActivator>(NULL, TEXT("/Game/FactoryGame/Buildable/Factory/FrackingSmasher/Build_FrackingSmasher.Build_FrackingSmasher_C")))
{
AFGBuildableFrackingActivator* FrackingActivatorDefault = BPBuildableFrackingActivator.GetDefaultObject();
frackingActivatorCDO = FrackingActivatorDefault;
FrackingActivatorDefault->mAllowedResources.AddUnique(mResourceClass);
}
if(const TSubclassOf<AFGBuildableFrackingExtractor> BPBuildableFrackingExtractor = LoadClass<AFGBuildableFrackingExtractor>(NULL, TEXT("/Game/FactoryGame/Buildable/Factory/FrackingExtractor/Build_FrackingExtractor.Build_FrackingExtractor_C")))
{
AFGBuildableFrackingExtractor* FrackingExtractorDefault = BPBuildableFrackingExtractor.GetDefaultObject();
frackingExtractorCDO = FrackingExtractorDefault;
FrackingExtractorDefault->mAllowedResources.AddUnique(mResourceClass);
}
}
이 예제에서 CDO 참조 속성은 frackingActivatorCDO
및 frackingExtractorCDO
입니다.
CDO를 올바르게 참조하려면, CDO를 변경하는 클래스에서 UObject*
유형의 속성을 생성합니다. 속성을 UPROPERTY
로 표시해야 UE가 속성을 인식할 수 있습니다.
여러 CDO를 수정하는 경우, 속성을 TArray<UObject*>
로 만들고 각 CDO를 배열에 추가할 수 있습니다.
기존 콘텐츠 확장하기
기존 콘텐츠에 새로운 동작을 추가해야 하는 경우, 이를 서브클래스를 만들어 확장하는 것이 더 쉬울 수 있습니다. 그런 다음 서브클래스에서 새로운 동작을 정의합니다.
이것은 자리 표시자 시스템과 잘 작동합니다. 실제 버전의 구현 세부정보는 없지만, 자리 표시자를 확장함으로써 런타임에서 이러한 기능을 여전히 사용할 수 있습니다.
후킹
CDO 수정이 작동하지 않거나 기존 콘텐츠를 확장할 수 없는 경우, 기존 함수에 후킹하여 원하는 수정을 수행할 수 있습니다.
후킹은 매우 복잡한 주제로, 자체 페이지에서 더 자세히 다루고 있습니다.