|
1 | 1 | #include "Data/FICScene.h" |
2 | 2 |
|
| 3 | +#include "ArchiveObjectTOCProxy.h" |
| 4 | +#include "BlueprintArchiveObjectDataProxy.h" |
| 5 | +#include "BlueprintArchiveObjectTOCProxy.h" |
3 | 6 | #include "FICSubsystem.h" |
4 | 7 | #include "FICUtils.h" |
| 8 | +#include "FileHelper.h" |
| 9 | +#include "NotificationManager.h" |
| 10 | +#include "ObjectWriter.h" |
| 11 | +#include "SaveCustomVersion.h" |
| 12 | +#include "SlateApplication.h" |
| 13 | +#include "SlateObjectReferenceCollector.h" |
| 14 | +#include "SNotificationList.h" |
| 15 | +#include "TextReferenceCollector.h" |
5 | 16 | #include "Editor/FICEditorSubsystem.h" |
6 | 17 | #include "Engine/GameViewportClient.h" |
7 | 18 | #include "Slate/SceneViewport.h" |
8 | 19 |
|
| 20 | +FCustomVersionRegistration GRegisterFICSceneVersion{FFICSceneVersion::GUID, FFICSceneVersion::Type::LatestVersion, TEXT("FicsIt-Cam Scene Version")}; |
| 21 | + |
9 | 22 | void AFICScene::PostLoadGame_Implementation(int32 saveVersion, int32 gameVersion) { |
10 | 23 | IFGSaveInterface::PostLoadGame_Implementation(saveVersion, gameVersion); |
11 | 24 |
|
@@ -71,3 +84,141 @@ bool AFICScene::IsSceneAlreadyInUse() { |
71 | 84 | FString ProcessKey = GetSceneProcessKey(SceneName); |
72 | 85 | return SubSys->GetActiveRuntimeProcessesMap().Contains(ProcessKey) || (EditSubSys->GetActiveEditorContext() && EditSubSys->GetActiveEditorContext()->GetScene() == this); |
73 | 86 | } |
| 87 | + |
| 88 | +class FFICSceneObjectCollector : public FArchiveUObject { |
| 89 | +private: |
| 90 | + TArray<UObject*>& ObjectsToSave; |
| 91 | + |
| 92 | +public: |
| 93 | + FFICSceneObjectCollector(TArray<UObject*>& toFill) : ObjectsToSave(toFill) { |
| 94 | + ArIsSaveGame = true; |
| 95 | + ArIsObjectReferenceCollector = true; |
| 96 | + } |
| 97 | + |
| 98 | + virtual FArchive& operator<<(UObject*& Object) override { |
| 99 | + if (!Object) return *this; |
| 100 | + if (Object->Implements<UFGSaveInterface>()) { |
| 101 | + if (IFGSaveInterface::Execute_ShouldSave(Object)) { |
| 102 | + ObjectsToSave.AddUnique(Object); |
| 103 | + Object->Serialize(*this); |
| 104 | + } |
| 105 | + } |
| 106 | + return *this; |
| 107 | + } |
| 108 | +}; |
| 109 | + |
| 110 | +class FFICSceneTOCProxy : public FArchiveProxy { |
| 111 | +public: |
| 112 | + UObject* NewOuter = nullptr; |
| 113 | + TMap<FString, UObject*> ObjectMap; |
| 114 | + |
| 115 | + FFICSceneTOCProxy(FArchive& Inner, UObject* NewOuter) : FArchiveProxy(Inner), NewOuter(NewOuter) {} |
| 116 | + |
| 117 | + virtual FArchive& operator<<(UObject*& Object) override { |
| 118 | + FString ClassPath; |
| 119 | + FString Name; |
| 120 | + FString Path; |
| 121 | + if (IsSaving() && Object) { |
| 122 | + ClassPath = Object->GetClass()->GetPathName(); |
| 123 | + Name = Object->GetName(); |
| 124 | + Path = Object->GetPathName(); |
| 125 | + } |
| 126 | + |
| 127 | + InnerArchive << ClassPath; |
| 128 | + InnerArchive << Name; |
| 129 | + InnerArchive << Path; |
| 130 | + |
| 131 | + if (IsLoading()) { |
| 132 | + UClass* Class = FSoftClassPath(ClassPath).TryLoadClass<UObject>(); |
| 133 | + if (Class) { |
| 134 | + Object = NewObject<UObject>(NewOuter, Class, FName(Name)); |
| 135 | + } |
| 136 | + ObjectMap.Add(Path, Object); |
| 137 | + } |
| 138 | + |
| 139 | + return *this; |
| 140 | + } |
| 141 | +}; |
| 142 | + |
| 143 | +class FFICSceneDataProxy : public FArchiveProxy { |
| 144 | +public: |
| 145 | + const TMap<FString, UObject*>& ObjectReplacementMap; |
| 146 | + |
| 147 | + FFICSceneDataProxy(FArchive& Inner, const TMap<FString, UObject*>& ObjectReplacementMap) : FArchiveProxy(Inner), ObjectReplacementMap(ObjectReplacementMap) {} |
| 148 | + |
| 149 | + virtual FArchive& operator<<(UObject*& Object) override { |
| 150 | + FString Path; |
| 151 | + if (IsSaving() && Object) { |
| 152 | + Path = Object->GetPathName(); |
| 153 | + } |
| 154 | + InnerArchive << Path; |
| 155 | + if (IsLoading() && !Path.IsEmpty()) { |
| 156 | + UObject* const* replacement = ObjectReplacementMap.Find(Path); |
| 157 | + if (replacement) { |
| 158 | + Object = *replacement; |
| 159 | + } else { |
| 160 | + Object = FSoftObjectPath(Path).TryLoad(); |
| 161 | + } |
| 162 | + } |
| 163 | + if (Object) { |
| 164 | + Object->Serialize(*this); |
| 165 | + } |
| 166 | + return *this; |
| 167 | + } |
| 168 | +}; |
| 169 | + |
| 170 | +void AFICScene::SerializeScene(TArray<UObject*>& ObjectsToSave, FArchive& Ar) { |
| 171 | + uint64 numObjects = ObjectsToSave.Num(); |
| 172 | + Ar << numObjects; |
| 173 | + ObjectsToSave.SetNumZeroed(numObjects); |
| 174 | + |
| 175 | + FFICSceneTOCProxy TOC(Ar, this); |
| 176 | + for (UObject*& Object : ObjectsToSave) { |
| 177 | + TOC << Object; |
| 178 | + } |
| 179 | + |
| 180 | + FFICSceneDataProxy DataProxy(Ar, TOC.ObjectMap); |
| 181 | + for (UObject* Object : ObjectsToSave) { |
| 182 | + DataProxy << Object; |
| 183 | + } |
| 184 | + this->Serialize(DataProxy); |
| 185 | +} |
| 186 | + |
| 187 | +void AFICScene::SaveToFile(const FString& Path) { |
| 188 | + TArray<UObject*> ObjectsToSave; |
| 189 | + FFICSceneObjectCollector Collector(ObjectsToSave); |
| 190 | + this->Serialize(Collector); |
| 191 | + |
| 192 | + TArray<uint8> Data; |
| 193 | + FMemoryWriter Ar(Data); |
| 194 | + Ar.ArIsSaveGame = true; |
| 195 | + Ar.UsingCustomVersion(FSaveCustomVersion::GUID); |
| 196 | + Ar.UsingCustomVersion(FFICSceneVersion::GUID); |
| 197 | + SerializeScene(ObjectsToSave, Ar); |
| 198 | + Ar.Close(); |
| 199 | + |
| 200 | + if (!FFileHelper::SaveArrayToFile(Data, *Path)) { |
| 201 | + FSlateNotificationManager::Get().AddNotification(FNotificationInfo(FText::FromString("Failed to save scene file: " + Path))); |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +void AFICScene::LoadFromFile(const FString& Path) { |
| 206 | + auto subsys = AFICEditorSubsystem::GetFICEditorSubsystem(this); |
| 207 | + |
| 208 | + subsys->CloseEditor(); |
| 209 | + FString name = this->SceneName; |
| 210 | + |
| 211 | + TArray<uint8> Data; |
| 212 | + if (!FFileHelper::LoadFileToArray(Data, *Path)) { |
| 213 | + FSlateNotificationManager::Get().AddNotification(FNotificationInfo(FText::FromString("Failed to load scene file: " + Path))); |
| 214 | + } |
| 215 | + |
| 216 | + TArray<UObject*> ObjectsToSave; |
| 217 | + FMemoryReader Ar(Data); |
| 218 | + Ar.ArIsSaveGame = true; |
| 219 | + SerializeScene(ObjectsToSave, Ar); |
| 220 | + |
| 221 | + this->SceneName = name; |
| 222 | + |
| 223 | + subsys->OpenEditor(this); |
| 224 | +} |
0 commit comments