저장 게임

저장 게임은 게임 세션 간 기계 및 상태 정보를 유지하는 데 필수적입니다. 저장 게임은 인벤토리에 있는 아이템과 같은 정보도 포함합니다. 일반적으로 새티스팩토리는 현재 게임 상태를 5분마다 자동으로 저장합니다. 물론, 게임 내에서 저장 버튼을 눌러 직접 게임 상태를 저장할 수도 있습니다.

저장 파일은 %localappdata%/FactoryGame/Saved/SaveGames/에서 찾을 수 있습니다.

하지만 "저장" 버튼을 누르면 실제로 어떤 일이 발생할까요?

게임 상태가 어떻게 저장됩니까?

저장 또는 로드가 발생할 때, 언리얼은 현재 로드된 세계를 직렬화합니다. 이 과정은 기본적으로 런타임의 모든 액터와 객체를 이진 데이터로 변환하여 나중에 다시 읽어 현재 런타임을 재구성할 수 있도록 합니다.

하지만 전체 런타임을 저장하지는 않습니다. 그렇게 되면 저장 파일이 너무 커지기 때문입니다. 따라서 직렬화에서는 여러 가지 방법으로 많은 것들이 제외됩니다. 기본적으로, 여러분의 객체는 직렬화되지 않으며, 언리얼에게 직렬화하고 싶다고 알려야 합니다.

세계의 모든 AActor 또는 UActorComponent는 직렬화될 것으로 간주되지만, 여전히 너무 많기 때문에, CSS는 IFGSaveInterface를 추가하여 추가 필터링을 가능하게 합니다. 직렬화하고 싶은 어떤 AActor가 있는 경우, ShouldSave 함수를 오버라이드하고 true를 반환해야 합니다.

액터가 직렬화될 때, 이는 두 단계로 진행됩니다.

첫 번째 단계에서는 언리얼 직렬화 과정이 실행되지만, 직렬화 가능한 UObject만 처리합니다. 따라서 이 단계에서는 직렬화해야 할 모든 UObject의 목록을 수집합니다. 그 후 CSS는 IFGSaveInterface::GatherDependencies의 결과를 고려하여 이 목록을 정렬합니다. 이것은 UObject가 의존하는 다른 UObject를 정의할 수 있도록 합니다.

이것은 저장 로드 시 역직렬화 단계에서 중요할 수 있습니다. 왜냐하면 의존하는 UObject가 먼저 완전히 역직렬화되기를 여러분이 원할 수 있기 때문입니다.

IFGSaveInterface::GatherDependencies를 사용할 때 순환 의존성을 유발하지 않도록 주의하십시오.

두 번째 단계에서는 이전에 결정된 UObject 순서를 고려하여 실제 언리얼 직렬화 과정이 실행됩니다.

"언리얼 직렬화"는 두 가지 방법으로 발생할 수 있으며, 자신의 직렬화 과정을 구현하거나 UProperties를 통해 언리얼의 기본 방식을 사용할 수 있습니다(권장). 필요한 경우, UObject 또는 구조체에 맞춤 직렬화를 추가하는 방법에 대한 자세한 내용은 언리얼 문서를 참고하십시오.

언리얼의 기본 직렬화 방식은 SkipSerialization 속성 플래그가 없고 SaveGame 속성 플래그가 있는 UProperties를 검색합니다. UPropertyUObject 참조인 경우, 해당 UObject도 직렬화됩니다.

이러한 직렬화가 진행되는 동안, 새티스팩토리 저장 시스템은 직렬화되는 모든 AActor에 대해 PreSaveGame, PostSaveGame, PreLoadGame, PostLoadGame 함수를 호출합니다.

이미지

SaveGame UProperty 플래그

모든 속성이 직렬화되는 것은 아닙니다. 오직 SaveGame 플래그가 있는 UProperties만 실제로 직렬화됩니다.

블루프린트 작업 시, 고급 속성 설정을 열고 SaveGame 박스를 체크하여 이 플래그를 추가할 수 있습니다.

C++ 작업 시, IFGSaveInterface를 사용하는 방법에 대한 지침을 따라야 합니다.

속성이나 객체에 SkipSerialization 플래그를 설정하지 않았는지 확인하십시오. 이렇게 되면 저장 시스템이 저장하려고 하지만 언리얼 직렬화기가 데이터를 무시하게 됩니다.

어쨌든, 기본적으로 설정되어 있지 않아야 합니다.

모든 유형이 직접 저장될 수 있는 것은 아닙니다. 이의 예로는 소프트 클래스 참조와 소프트 객체 참조 유형이 있습니다. 이 경우, 위에서 설명한 대로 해당 유형을 직접 직렬화하는 코드를 작성해야 합니다. 소프트 클래스 참조의 예를 들자면, 소프트 클래스 참조 속성을 저장하는 대신, 저장된 문자열 속성을 사용하여 PreSaveGame에서 복사하고 PostLoadGame에서 "실제" 필드를 채워야 합니다.

IFGSaveInterface

새티스팩토리의 저장 시스템은 IFGSaveInterface를 사용하여 저장해야 할 객체와 그렇지 않은 객체를 필터링합니다.

가장 중요한 함수 중 하나는 bool ShouldSave() const 함수로, 객체가 저장되어야 할 때 true를 반환합니다. 이는 객체의 상태에 따라 달라질 수 있습니다. 예를 들어, 나무는 실제로 게임에서 베어졌을 때만 true를 반환합니다.

즉, 게임 세션 간에 유지하고 싶은 정보가 있다면, IFGSaveInterface를 구현하고 ShouldSave에서 true를 반환해야 합니다.

FGBuildable은 이미 IFGSaveInterface를 구현했지만 ShouldSave에서 true를 반환하지 않으므로, 반드시 이 함수를 오버라이드하고 true를 반환해야 합니다.

다른 모든 함수는 저장 상태가 저장되거나 로드될 때 직렬화 및 필터링 과정을 추가로 맞춤 설정할 수 있게 합니다.

플레이어별 데이터 저장

멀티플레이 게임에서 건물이나 장비와 같은 구체적인 게임 객체에 묶이지 않고 플레이어별로 데이터를 저장해야 하는 상황이 발생할 수 있습니다. 이를 구현하는 가장 좋은 방법은 간단 구축 스크립트(SCS) 훅을 사용하는 것입니다.

모드 저장 콘텐츠가 위치하는 곳

원하는 경우, 모드 저장을 에디터에서 확인하여 데이터가 어떻게 저장되는지 살펴볼 수 있습니다.

일반적으로 모드에서 생성된 콘텐츠는 Game/<모드_참조>/ 태그 아래에 나타납니다.

아래는 NogsOres라는 참조가 있는 모드의 데이터를 표시하는 SatisfactorySaveEditor의 스크린샷입니다.

이미지

저장 파일 구조

저장 파일 형식에 대한 자세한 내용은 다음 자원을 통해 확인할 수 있습니다: