Skip to content

Commit 2c8d39c

Browse files
authored
Merge pull request #52 from Panakotta00/development
Development
2 parents 6fea47f + 3b1cb36 commit 2c8d39c

File tree

11 files changed

+285
-18
lines changed

11 files changed

+285
-18
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,8 @@ jobs:
7070
- name: Build for Shipping/Client Steam
7171
run: ${{ github.workspace }}\\ue\\Engine\\Build\\BatchFiles\\Build.bat FactoryGameSteam Win64 Shipping -project='${{ github.workspace }}\SatisfactoryModLoader\FactoryGame.uproject'
7272

73-
7473
- name: Package FicsItCam Mod
75-
run: ${{ github.workspace }}\ue\Engine\Build\BatchFiles\RunUAT.bat -ScriptsForProject='${{ github.workspace }}\SatisfactoryModLoader\FactoryGame.uproject' PackagePlugin -project='${{ github.workspace }}\SatisfactoryModLoader\FactoryGame.uproject' -DLCName='FicsItCam' -build -server -clientconfig=Shipping -serverconfig=Shipping -platform=Win64 -nocompileeditor -installed -merge -utf8output
74+
run: ${{ github.workspace }}\ue\Engine\Build\BatchFiles\RunUAT.bat -ScriptsForProject='${{ github.workspace }}\SatisfactoryModLoader\FactoryGame.uproject' PackagePlugin -project='${{ github.workspace }}\SatisfactoryModLoader\FactoryGame.uproject' -DLCName='FicsItCam' -build -clientconfig=Shipping -platform=Win64 -nocompileeditor -installed -merge -utf8output
7675

7776
- name: Upload FicsItCam-Merged
7877
id: upload-win64-merged

FicsItCam.uplugin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"FileVersion": 3,
33
"Version": 1,
44
"VersionName": "1.0",
5-
"SemVersion": "1.0.1",
5+
"SemVersion": "1.0.2",
66
"GameVersion": ">=415558",
77
"AcceptsAnyRemoteVersion": true,
88
"FriendlyName": "FicsIt-Cam",

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# FicsItCam [![Build Status](https://jenkins.massivebytes.net/job/FicsIt-Cam/job/master/badge/icon)](https://jenkins.massivebytes.net/job/FicsIt-Cam/job/master/)
1+
# FicsItCam
22

33
This Satisfactory mod is mainly intended for Content Creators to allow the creation of beautiful camera animations, timelapse recordings and other camera related things.
44

Source/FicsItCam/Private/Data/Attributes/FICAttributeGroup.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,13 @@ void FFICGroupAttribute::AddChildAttribute(FString Name, FFICAttribute* Attribut
9696
}
9797

9898
void FFICGroupAttribute::RemoveChildAttribute(FString Name) {
99-
Children[Name]->OnUpdate.Remove(UpdateDelegateHandles[Name]);
100-
Children.Remove(Name);
101-
UpdateDelegateHandles.Remove(Name);
99+
FFICAttribute** Attribute = Children.Find(Name);
100+
FDelegateHandle* Handle = UpdateDelegateHandles.Find(Name);
101+
if (Handle) {
102+
Children[Name]->OnUpdate.Remove(UpdateDelegateHandles[Name]);
103+
Children.Remove(Name);
104+
}
105+
if (Attribute) {
106+
UpdateDelegateHandles.Remove(Name);
107+
}
102108
}

Source/FicsItCam/Private/Data/FICScene.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
#include "Data/FICScene.h"
22

3+
#include "ArchiveObjectTOCProxy.h"
4+
#include "BlueprintArchiveObjectDataProxy.h"
5+
#include "BlueprintArchiveObjectTOCProxy.h"
36
#include "FICSubsystem.h"
47
#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"
516
#include "Editor/FICEditorSubsystem.h"
617
#include "Engine/GameViewportClient.h"
718
#include "Slate/SceneViewport.h"
819

20+
FCustomVersionRegistration GRegisterFICSceneVersion{FFICSceneVersion::GUID, FFICSceneVersion::Type::LatestVersion, TEXT("FicsIt-Cam Scene Version")};
21+
922
void AFICScene::PostLoadGame_Implementation(int32 saveVersion, int32 gameVersion) {
1023
IFGSaveInterface::PostLoadGame_Implementation(saveVersion, gameVersion);
1124

@@ -71,3 +84,141 @@ bool AFICScene::IsSceneAlreadyInUse() {
7184
FString ProcessKey = GetSceneProcessKey(SceneName);
7285
return SubSys->GetActiveRuntimeProcessesMap().Contains(ProcessKey) || (EditSubSys->GetActiveEditorContext() && EditSubSys->GetActiveEditorContext()->GetScene() == this);
7386
}
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+
}

Source/FicsItCam/Private/Editor/FICEditorContext.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,20 @@ void UFICEditorContext::UnloadSceneObject(UObject* SceneObject) {
138138
if (GetSelectedSceneObject() == SceneObject) SetSelectedSceneObject(nullptr);
139139

140140
AllAttributes->RemoveAttribute(FString::FromInt(SceneObject->GetUniqueID()));
141-
EditorAttributes[SceneObject]->GetAttribute().OnUpdate.Remove(DataAttributeOnUpdateDelegateHandles[SceneObject]);
142-
TFunction<void(TSharedRef<FFICEditorAttributeBase>)> RemoveEditAttrib;
143-
RemoveEditAttrib = [this, &RemoveEditAttrib](TSharedRef<FFICEditorAttributeBase> Attrib) {
144-
EditorAttributeMap.Remove(&Attrib->GetAttribute());
145-
for (const TPair<FString, TSharedRef<FFICEditorAttributeBase>>& Child : Attrib->GetChildAttributes()) {
146-
RemoveEditAttrib(Child.Value);
147-
}
148-
};
149-
RemoveEditAttrib(EditorAttributes[SceneObject]);
150-
EditorAttributes.Remove(SceneObject);
141+
auto attribute = EditorAttributes.Find(SceneObject);
142+
if (!attribute) {
143+
auto attr = *attribute;
144+
attr->GetAttribute().OnUpdate.Remove(DataAttributeOnUpdateDelegateHandles[SceneObject]);
145+
TFunction<void(TSharedRef<FFICEditorAttributeBase>)> RemoveEditAttrib;
146+
RemoveEditAttrib = [this, &RemoveEditAttrib](TSharedRef<FFICEditorAttributeBase> Attrib) {
147+
EditorAttributeMap.Remove(&Attrib->GetAttribute());
148+
for (const TPair<FString, TSharedRef<FFICEditorAttributeBase>>& Child : Attrib->GetChildAttributes()) {
149+
RemoveEditAttrib(Child.Value);
150+
}
151+
};
152+
RemoveEditAttrib(attr);
153+
EditorAttributes.Remove(SceneObject);
154+
}
151155
DataAttributeOnUpdateDelegateHandles.Remove(SceneObject);
152156

153157
ActiveSceneObjectManager.UpdateActiveObjects(GetCurrentFrame());

Source/FicsItCam/Private/Editor/UI/FICEditor.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Editor/UI/FICEditor.h"
22

33
#include "FICConfigurationStruct.h"
4+
#include "FICUIUtil.h"
45
#include "FICUtils.h"
56
#include "SButton.h"
67
#include "SEditableTextBox.h"
@@ -158,6 +159,20 @@ FMenuBarBuilder SFICEditor::CreateMenuBar() {
158159
FSlateApplication::Get().ClearAllUserFocus();
159160
AFICEditorSubsystem::GetFICEditorSubsystem(Context->GetScene()->GetWorld())->CloseEditor();
160161
}));
162+
MenuBarBuilder.AddPullDownMenu(LOCTEXT("File", "File"), LOCTEXT("FileTT", "File Operations"), FNewMenuDelegate::CreateLambda([this](FMenuBuilder& MenuBuilder) {
163+
MenuBuilder.AddMenuEntry(LOCTEXT("Export", "Export"), LOCTEXT("ExportTT", "Export this scene as file"), FSlateIcon(), FExecuteAction::CreateLambda([this]() {
164+
TOptional<FString> path = FICSaveSceneFileDialog(Context->GetScene()->SceneName);
165+
if (path) {
166+
Context->GetScene()->SaveToFile(*path);
167+
}
168+
}));
169+
MenuBuilder.AddMenuEntry(LOCTEXT("Import", "Import"), LOCTEXT("ImportTT", "Import a scene from file"), FSlateIcon(), FExecuteAction::CreateLambda([this]() {
170+
TOptional<FString> path = FICOpenSceneFileDialog();
171+
if (path) {
172+
Context->GetScene()->LoadFromFile(*path);
173+
}
174+
}));
175+
}));
161176
MenuBarBuilder.AddPullDownMenu(LOCTEXT("View", "View"), LOCTEXT("ViewTT", "Views, Panels & Windows"), FNewMenuDelegate::CreateLambda([this](FMenuBuilder& MenuBuilder) {
162177
TabManager->PopulateLocalTabSpawnerMenu(MenuBuilder);
163178
}));

Source/FicsItCam/Private/Editor/UI/FICUIUtil.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "Editor/UI/FICUIUtil.h"
22

3+
#include "SlateApplication.h"
4+
35
FMenuBuilder FICCreateKeyframeTypeChangeMenu(UFICEditorContext* Context, TFunction<TSet<TPair<FFICAttribute*, FICFrame>>()> GetKeyframes) {
46
TFunction<void(EFICKeyframeType)> SetKeyframeType;
57
SetKeyframeType = [GetKeyframes, Context](EFICKeyframeType Type) {
@@ -56,3 +58,70 @@ FMenuBuilder FICCreateKeyframeTypeChangeMenu(UFICEditorContext* Context, TFuncti
5658

5759
return MenuBuilder;
5860
}
61+
62+
#include "MinWindows.h"
63+
#include "Microsoft/COMPointer.h"
64+
#include "Windows/AllowWindowsPlatformTypes.h"
65+
#include <commdlg.h>
66+
#include <shellapi.h>
67+
#include <shlobj.h>
68+
#include <LM.h>
69+
#include "Windows/HideWindowsPlatformTypes.h"
70+
71+
#pragma comment( lib, "version.lib" )
72+
73+
TOptional<FString> FileDialog(bool bSave, const FString& Title, const FString& DefaultFile, const FString& DefaultPath) {
74+
TComPtr<IFileDialog> FileDialog;
75+
if (SUCCEEDED(::CoCreateInstance(
76+
bSave ? CLSID_FileSaveDialog : CLSID_FileOpenDialog,
77+
nullptr,
78+
CLSCTX_INPROC_SERVER,
79+
bSave ? IID_IFileSaveDialog : IID_IFileOpenDialog,
80+
IID_PPV_ARGS_Helper(&FileDialog)
81+
))) {
82+
FileDialog->SetTitle(*Title);
83+
if (!DefaultFile.IsEmpty()) {
84+
FileDialog->SetFileName(*DefaultFile);
85+
}
86+
87+
if (!DefaultPath.IsEmpty()) {
88+
FString DefaultWindowsPath = FPaths::ConvertRelativePathToFull(DefaultPath);
89+
DefaultWindowsPath.ReplaceInline(TEXT("/"), TEXT("\\"), ESearchCase::CaseSensitive);
90+
TComPtr<IShellItem> DefaultPathItem;
91+
if (SUCCEEDED(::SHCreateItemFromParsingName(*DefaultWindowsPath, nullptr, IID_PPV_ARGS(&DefaultPathItem)))) {
92+
FileDialog->SetFolder(DefaultPathItem);
93+
}
94+
}
95+
96+
COMDLG_FILTERSPEC rgSpec[] = {
97+
{ TEXT("FicsIt-Cam Scene"), L"*.fic_scene" },
98+
};
99+
FileDialog->SetFileTypes(1, rgSpec);
100+
FileDialog->SetDefaultExtension(TEXT("fic_scene"));
101+
if (SUCCEEDED(FileDialog->Show(nullptr))) {
102+
TComPtr<IShellItem> Result;
103+
if (SUCCEEDED(FileDialog->GetResult(&Result))) {
104+
PWSTR pFilePath = nullptr;
105+
if (SUCCEEDED(Result->GetDisplayName(SIGDN_FILESYSPATH, &pFilePath))) {
106+
FString filePath = pFilePath;
107+
::CoTaskMemFree(pFilePath);
108+
FPaths::NormalizeFilename(filePath);
109+
return filePath;
110+
}
111+
}
112+
}
113+
}
114+
return {};
115+
}
116+
117+
TOptional<FString> FICSaveSceneFileDialog(const FString& SceneName) {
118+
FString DefaultFile = FString::Printf(TEXT("%ls.fic_scene"), *SceneName);
119+
FString DefaultPath = FPlatformProcess::UserDir();
120+
121+
return FileDialog(true, TEXT("Export FicsIt-Cam Scene..."), DefaultFile, DefaultPath);
122+
}
123+
124+
TOptional<FString> FICOpenSceneFileDialog() {
125+
FString DefaultPath = FPlatformProcess::UserDir();
126+
return FileDialog(false, TEXT("Import FicsIt-Cam Scene..."), FString(), DefaultPath);
127+
}

Source/FicsItCam/Private/Util/FICProceduralTexture.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ void UFICProceduralTexture::ReloadData() {
3838
PrimaryMipMap.BulkData.Unlock();
3939

4040
FFunctionGraphTask::CreateAndDispatchWhenReady([this]() {
41+
if (Texture == nullptr) return;
4142
Texture->UpdateResource();
4243
OnTextureUpdate.Broadcast();
4344
}, TStatId(), nullptr, ENamedThreads::GameThread);

Source/FicsItCam/Public/Data/FICScene.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
#include "Util/FICProceduralTexture.h"
99
#include "FICScene.generated.h"
1010

11+
struct FICSITCAM_API FFICSceneVersion {
12+
enum Type {
13+
NoVersion,
14+
15+
InitialVersion,
16+
17+
VersionPlusOne,
18+
LatestVersion = VersionPlusOne - 1
19+
};
20+
21+
inline static const FGuid GUID = FGuid( 0x04730e5a, 0x04414b85, 0xaa76f90a, 0x57a43a21 );
22+
23+
inline static const TCHAR Name[] = TEXT( "RuntimeBuildableInstanceVersion" );
24+
};
25+
1126
UCLASS()
1227
class FICSITCAM_API AFICScene : public AActor, public IFGSaveInterface {
1328
GENERATED_BODY()
@@ -96,4 +111,8 @@ class FICSITCAM_API AFICScene : public AActor, public IFGSaveInterface {
96111

97112
UFUNCTION(BlueprintCallable)
98113
bool IsSceneAlreadyInUse();
114+
115+
void SerializeScene(TArray<UObject*>& ObjectsToSave, FArchive& Ar);
116+
void SaveToFile(const FString& Path);
117+
void LoadFromFile(const FString& Path);
99118
};

0 commit comments

Comments
 (0)