aboutsummaryrefslogtreecommitdiff
path: root/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'Plugins')
-rw-r--r--Plugins/SimpleUGC/Resources/ButtonIcon_40x.pngbin0 -> 9212 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/CreateUGC_128x.pngbin0 -> 9780 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/CreateUGC_16x.pngbin0 -> 2149 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/CreateUGC_48x.pngbin0 -> 3266 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/CreateUGC_64x.pngbin0 -> 4567 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/Icon128.pngbin0 -> 13381 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/PackageUGC_128x.pngbin0 -> 6324 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/PackageUGC_16x.pngbin0 -> 2055 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/PackageUGC_48x.pngbin0 -> 2163 bytes
-rw-r--r--Plugins/SimpleUGC/Resources/PackageUGC_64x.pngbin0 -> 2915 bytes
-rw-r--r--Plugins/SimpleUGC/SimpleUGC.uplugin34
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/MakeReplaceableActorComponent.cpp9
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/ReplacementActorComponent.cpp9
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/SimpleUGC.cpp8
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBaseGameInstance.cpp11
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBlueprintLibrary.cpp13
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp241
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2b8431a.TMP262
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2bf9f51.TMP319
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/MakeReplaceableActorComponent.h22
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/ReplacementActorComponent.h21
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/SimpleUGC.h10
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBaseGameInstance.h25
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBlueprintLibrary.h20
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h98
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h~RF2b28773.TMP106
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGC/SimpleUGC.Build.cs59
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCCreator.cpp65
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditor.cpp130
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorCommands.cpp51
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorStyle.cpp72
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPackager.cpp205
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPluginWizardDefinition.cpp214
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCCreator.h33
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditor.h41
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorCommands.h27
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorStyle.h31
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPackager.h49
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPluginWizardDefinition.h70
-rw-r--r--Plugins/SimpleUGC/Source/SimpleUGCEditor/SimpleUGCEditor.Build.cs59
-rw-r--r--Plugins/SimpleUGC/Templates/BaseTemplate/Resources/Icon128.pngbin0 -> 13381 bytes
41 files changed, 2314 insertions, 0 deletions
diff --git a/Plugins/SimpleUGC/Resources/ButtonIcon_40x.png b/Plugins/SimpleUGC/Resources/ButtonIcon_40x.png
new file mode 100644
index 0000000..2e8bbfd
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/ButtonIcon_40x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/CreateUGC_128x.png b/Plugins/SimpleUGC/Resources/CreateUGC_128x.png
new file mode 100644
index 0000000..5ffc3c6
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/CreateUGC_128x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/CreateUGC_16x.png b/Plugins/SimpleUGC/Resources/CreateUGC_16x.png
new file mode 100644
index 0000000..f61daf0
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/CreateUGC_16x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/CreateUGC_48x.png b/Plugins/SimpleUGC/Resources/CreateUGC_48x.png
new file mode 100644
index 0000000..a958056
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/CreateUGC_48x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/CreateUGC_64x.png b/Plugins/SimpleUGC/Resources/CreateUGC_64x.png
new file mode 100644
index 0000000..c4278cd
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/CreateUGC_64x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/Icon128.png b/Plugins/SimpleUGC/Resources/Icon128.png
new file mode 100644
index 0000000..85b65e7
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/Icon128.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/PackageUGC_128x.png b/Plugins/SimpleUGC/Resources/PackageUGC_128x.png
new file mode 100644
index 0000000..4221113
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/PackageUGC_128x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/PackageUGC_16x.png b/Plugins/SimpleUGC/Resources/PackageUGC_16x.png
new file mode 100644
index 0000000..cbe6e06
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/PackageUGC_16x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/PackageUGC_48x.png b/Plugins/SimpleUGC/Resources/PackageUGC_48x.png
new file mode 100644
index 0000000..8ca1ebd
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/PackageUGC_48x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/Resources/PackageUGC_64x.png b/Plugins/SimpleUGC/Resources/PackageUGC_64x.png
new file mode 100644
index 0000000..0657a05
--- /dev/null
+++ b/Plugins/SimpleUGC/Resources/PackageUGC_64x.png
Binary files differ
diff --git a/Plugins/SimpleUGC/SimpleUGC.uplugin b/Plugins/SimpleUGC/SimpleUGC.uplugin
new file mode 100644
index 0000000..ac3cf0a
--- /dev/null
+++ b/Plugins/SimpleUGC/SimpleUGC.uplugin
@@ -0,0 +1,34 @@
+{
+ "FileVersion": 3,
+ "Version": 1,
+ "VersionName": "1.0",
+ "FriendlyName": "SimpleUGC",
+ "Description": "",
+ "Category": "Other",
+ "CreatedBy": "",
+ "CreatedByURL": "",
+ "DocsURL": "",
+ "MarketplaceURL": "",
+ "SupportURL": "",
+ "CanContainContent": true,
+ "IsBetaVersion": false,
+ "Installed": false,
+ "Modules": [
+ {
+ "Name": "SimpleUGC",
+ "Type": "Runtime",
+ "LoadingPhase": "PreLoadingScreen"
+ },
+ {
+ "Name": "SimpleUGCEditor",
+ "Type": "Editor",
+ "LoadingPhase": "Default"
+ }
+ ],
+ "Plugins": [
+ {
+ "Name": "PluginBrowser",
+ "Enabled": true
+ }
+ ]
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/MakeReplaceableActorComponent.cpp b/Plugins/SimpleUGC/Source/SimpleUGC/Private/MakeReplaceableActorComponent.cpp
new file mode 100644
index 0000000..3e3d638
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/MakeReplaceableActorComponent.cpp
@@ -0,0 +1,9 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "MakeReplaceableActorComponent.h"
+
+// Sets default values for this component's properties
+UMakeReplaceableActorComponent::UMakeReplaceableActorComponent()
+{
+ SetAutoActivate(true);
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/ReplacementActorComponent.cpp b/Plugins/SimpleUGC/Source/SimpleUGC/Private/ReplacementActorComponent.cpp
new file mode 100644
index 0000000..773cec8
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/ReplacementActorComponent.cpp
@@ -0,0 +1,9 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "ReplacementActorComponent.h"
+
+// Sets default values for this component's properties
+UReplacementActorComponent::UReplacementActorComponent()
+{
+ SetAutoActivate(true);
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/SimpleUGC.cpp b/Plugins/SimpleUGC/Source/SimpleUGC/Private/SimpleUGC.cpp
new file mode 100644
index 0000000..67ee730
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/SimpleUGC.cpp
@@ -0,0 +1,8 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "SimpleUGC.h"
+
+#define LOCTEXT_NAMESPACE "FSimpleUGCModule"
+#undef LOCTEXT_NAMESPACE
+
+IMPLEMENT_MODULE(FSimpleUGCModule, SimpleUGC)
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBaseGameInstance.cpp b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBaseGameInstance.cpp
new file mode 100644
index 0000000..39ef343
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBaseGameInstance.cpp
@@ -0,0 +1,11 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "UGCBaseGameInstance.h"
+
+void UUGCBaseGameInstance::Init()
+{
+ // Instnatiate the registry and find mod packages
+ UGCRegistry = NewObject<UUGCRegistry>(this);
+ UGCRegistry->FindUGCPackages();
+ Super::Init();
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBlueprintLibrary.cpp b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBlueprintLibrary.cpp
new file mode 100644
index 0000000..39956f9
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCBlueprintLibrary.cpp
@@ -0,0 +1,13 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "UGCBlueprintLibrary.h"
+#include "UGCBaseGameInstance.h"
+#include "UGCRegistry.h"
+#include "Kismet/GameplayStatics.h"
+#include "SimpleUGC.h"
+
+UUGCRegistry * UUGCBlueprintLibrary::GetUGCRegistry(UObject* WorldContextObject)
+{
+ UUGCBaseGameInstance* GameInstance = Cast<UUGCBaseGameInstance>(UGameplayStatics::GetGameInstance(WorldContextObject));
+ return (GameInstance) ? GameInstance->UGCRegistry : nullptr;
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp
new file mode 100644
index 0000000..90680fb
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp
@@ -0,0 +1,241 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "UGCRegistry.h"
+#include "AssetRegistryModule.h"
+#include "ARFilter.h"
+#include "Interfaces/IPluginManager.h"
+#include "HAL/PlatformFilemanager.h"
+#include "Runtime/Json/Public/Dom/JsonObject.h"
+#include "Misc/PackageName.h"
+#include "Kismet/GameplayStatics.h"
+#include "Misc/Paths.h"
+#include "MakeReplaceableActorComponent.h"
+#include "ReplacementActorComponent.h"
+#include "SimpleUGC.h"
+
+bool UUGCRegistry::FindUGCPackages()
+{
+ TArray<TSharedRef<IPlugin>> EnabledPlugins = IPluginManager::Get().GetEnabledPlugins();
+ for (const TSharedRef<IPlugin>& Plugin : EnabledPlugins)
+ {
+ if (Plugin->GetLoadedFrom() == EPluginLoadedFrom::Project && Plugin->GetDescriptor().Category == "UGC")
+ {
+ FUGCPackage Package;
+ Package.PackagePath = *Plugin->GetMountedAssetPath().LeftChop(1);
+ Package.EngineVersion = *Plugin->GetDescriptor().EngineVersion;
+ Package.Author = *Plugin->GetDescriptor().CreatedBy;
+ Package.Description = *Plugin->GetDescriptor().Description;
+ UGCPackages.Add(Package);
+ }
+ }
+
+ return UGCPackages.Num() > 0;
+}
+
+bool UUGCRegistry::GetAllClassesInPackage(FUGCPackage Package, TArray<UClass*> &Classes)
+{
+ // Load up the AssetRegistry, Filter for Blueprints
+
+ IAssetRegistry& AssetRegistry = GetAsstRegistry();
+ FARFilter ARFilter;
+ TArray<FAssetData> AssetList;
+ ARFilter.bRecursivePaths = true;
+ ARFilter.bIncludeOnlyOnDiskAssets = true;
+ ARFilter.bRecursiveClasses = true;
+ ARFilter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
+ ARFilter.PackagePaths.Add(FName(*Package.PackagePath));
+ AssetRegistry.GetAssets(ARFilter, AssetList);
+
+ for (FAssetData Asset : AssetList)
+ {
+ FAssetDataTagMapSharedView::FFindTagResult GeneratedClassResult = Asset.TagsAndValues.FindTag("GeneratedClass");
+ if (GeneratedClassResult.IsSet())
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*GeneratedClassResult.GetValue());
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ if (AssetClass)
+ {
+ Classes.Add(AssetClass);
+ }
+ }
+ }
+
+ return Classes.Num() > 0;
+}
+
+bool UUGCRegistry::GetMapsInPackage(FUGCPackage Package, TArray<FName> &Maps)
+{
+ // Load up the AssetRegistry, FIlter for Maps
+ IAssetRegistry& AssetRegistry = GetAsstRegistry();
+ FARFilter ARFilter;
+ TArray<FAssetData> AssetList;
+ ARFilter.bRecursivePaths = true;
+ ARFilter.bIncludeOnlyOnDiskAssets = true;
+ ARFilter.bRecursiveClasses = true;
+ ARFilter.ClassNames.Add(UWorld::StaticClass()->GetFName());
+ ARFilter.PackagePaths.Add(FName(*Package.PackagePath));
+ AssetRegistry.GetAssets(ARFilter, AssetList);
+
+ for (FAssetData Asset : AssetList)
+ {
+ Maps.Add(Asset.AssetName);
+ }
+
+ return Maps.Num() > 0;
+}
+
+bool UUGCRegistry::GetActorClassesWithReplacementActorComponentsInPackage(FUGCPackage Package, TArray<TSubclassOf<AActor>> &ActorClasses)
+{
+ // Load up the AssetRegistry, Filter for Blueprints
+ IAssetRegistry& AssetRegistry = GetAsstRegistry();
+ FARFilter ARFilter;
+ TArray<FAssetData> AssetList;
+ ARFilter.bRecursivePaths = true;
+ ARFilter.bIncludeOnlyOnDiskAssets = true;
+ ARFilter.bRecursiveClasses = true;
+ ARFilter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
+ ARFilter.PackagePaths.Add(FName(*Package.PackagePath));
+ AssetRegistry.GetAssets(ARFilter, AssetList);
+
+ for (FAssetData Asset : AssetList)
+ {
+ FAssetDataTagMapSharedView::FFindTagResult GeneratedClassResult = Asset.TagsAndValues.FindTag("GeneratedClass");
+ if (GeneratedClassResult.IsSet())
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*GeneratedClassResult.GetValue());
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ if (AssetClass)
+ {
+
+ if (UBlueprintGeneratedClass* BlueprintModClass = Cast<UBlueprintGeneratedClass>(AssetClass))
+ {
+ // Not All Blueprint Classes have a SCS, so ensure that it has one before we get at dem nodes.
+ if (BlueprintModClass->SimpleConstructionScript != nullptr)
+ {
+ // Find UGCOverrideComponent
+ for (USCS_Node* Node : BlueprintModClass->SimpleConstructionScript->GetRootNodes())
+ {
+ // If we found it, add to Classes
+ if (UReplacementActorComponent * ReplacementActorComponent = Cast<UReplacementActorComponent>(Node->ComponentTemplate))
+ {
+ ActorClasses.Add(AssetClass);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return ActorClasses.Num() > 0;
+}
+bool UUGCRegistry::ApplyAllOverridesInPackage(FUGCPackage Package)
+{
+ bool bSuccess = false;
+ // Load up the AssetRegistry
+ IAssetRegistry& AssetRegistry = GetAsstRegistry();
+ TArray<FAssetData> AssetList;
+ AssetRegistry.GetAssetsByPath(FName(*Package.PackagePath), AssetList, true);
+
+ for (FAssetData Asset : AssetList)
+ {
+ FAssetDataTagMapSharedView::FFindTagResult GeneratedClassResult = Asset.TagsAndValues.FindTag("GeneratedClass");
+ if (GeneratedClassResult.IsSet())
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*GeneratedClassResult.GetValue());
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Try to apply an override
+ if (AssetClass)
+ {
+ bSuccess = ApplyOverridesForActorClass(AssetClass) || bSuccess;
+ }
+ }
+ }
+ return bSuccess;
+}
+
+bool UUGCRegistry::ApplyOverridesForActorClass(TSubclassOf<AActor> ActorClass)
+{
+ bool bSuccess = false;
+
+ // Check Blueprints
+ if (UBlueprintGeneratedClass* BlueprintActorClass = Cast<UBlueprintGeneratedClass>(ActorClass))
+ {
+ // Null check on SCS
+ if (BlueprintActorClass->SimpleConstructionScript != nullptr)
+ {
+ // Find UGCOverrideComponent so we know what to override
+ for (USCS_Node* Node : BlueprintActorClass->SimpleConstructionScript->GetRootNodes())
+ {
+ // If we found it,
+ if (UReplacementActorComponent* ReplacementActorComponent = Cast<UReplacementActorComponent>(Node->ComponentTemplate))
+ {
+ // Check The Classes To Override
+ for (UClass* ActorClassToReplace : ReplacementActorComponent->ActorClassesToReplace)
+ {
+ // Check Blueprint First..
+ if (UBlueprintGeneratedClass* BlueprintClassToReplace = Cast< UBlueprintGeneratedClass>(ActorClassToReplace))
+ {
+ if (BlueprintClassToReplace->SimpleConstructionScript != nullptr)
+ {
+ // Null check on SCS
+ for (USCS_Node* ActorClassToReplaceNode : BlueprintClassToReplace->SimpleConstructionScript->GetRootNodes())
+ {
+ // Find UGCOverrideableComponent so we can ensure compatibility
+ if (UMakeReplaceableActorComponent* MakeReplaceableActorComponent = Cast<UMakeReplaceableActorComponent>(ActorClassToReplaceNode->ComponentTemplate))
+ {
+ // Ensure compatibility
+ if (ActorClass->IsChildOf(MakeReplaceableActorComponent->CompatibleReplacement))
+ {
+ // Register
+ RegisterOverrideForClass(ActorClassToReplace, ActorClass);
+ bSuccess = true;
+ }
+ }
+ }
+ }
+ }
+ // If doing code mods, implement check for UUGCOverrideableComponent on non BP classes here.
+ // else{}
+ }
+ }
+ }
+ }
+ }
+ // If doing code mods, implement check for UUGCOverrideComponent on non-BP classes here.
+ // else{}
+
+ return bSuccess;
+}
+
+void UUGCRegistry::RegisterOverrideForClass(TSubclassOf<AActor> ClassToOverride, TSubclassOf<AActor> OverrideClass)
+{
+ RegisteredOverrides.Emplace(ClassToOverride, OverrideClass);
+}
+
+void UUGCRegistry::ClearOverrideForClass(TSubclassOf<AActor> ActorClass)
+{
+ RegisteredOverrides.Remove(ActorClass);
+}
+
+TSubclassOf<AActor> UUGCRegistry::GetOverrideForActorClass(TSubclassOf<AActor> ActorClass)
+{
+ if (RegisteredOverrides.Contains(ActorClass))
+ {
+ return *RegisteredOverrides.Find(ActorClass);
+ }
+ return ActorClass;
+}
+
+IAssetRegistry& UUGCRegistry::GetAsstRegistry()
+{
+ if (!CachedAssetRegistryModule)
+ {
+ CachedAssetRegistryModule = &FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
+ }
+
+ check(CachedAssetRegistryModule);
+ return CachedAssetRegistryModule->Get();
+} \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2b8431a.TMP b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2b8431a.TMP
new file mode 100644
index 0000000..ab0d98e
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2b8431a.TMP
@@ -0,0 +1,262 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "UGCRegistry.h"
+#include "UGCKit.h"
+
+
+
+bool UUGCRegistry::FindUGCPackages()
+{
+ // Now let's find all new root paths in the asset registry.
+ TArray<FString> RootPaths;
+ FPackageName::QueryRootContentPaths(RootPaths);
+
+ // Remove any plugins your game is shipping with, as well as engine and game roots. We only care about NEW paths.
+ RootPaths.Remove(TEXT("/Engine/"));
+ RootPaths.Remove(TEXT("/Game/"));
+ RootPaths.Remove(TEXT("/Paper2D/"));
+ RootPaths.Remove(TEXT("/UGCKit/"));
+
+ // Remove any other plugins you've defined in Blueprints
+ for (FName Package : PackageBlacklist)
+ {
+ RootPaths.Remove(Package.ToString());
+ }
+
+ if (RootPaths.Num() <= 0)
+ {
+ return false;
+ }
+
+ for (FString Path : RootPaths)
+ {
+ UGCPackages.Add(FName(*Path.LeftChop(1)));
+ }
+
+ return true;
+
+}
+
+bool UUGCRegistry::GetAssetsFromPackage(FName Package, TArray<FAssetData> &Assets, bool bOnlyRegisteredModTypes)
+{
+ // Load up the AssetRegistry
+ FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
+ IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
+
+ TArray<FAssetData> AssetList;
+ AssetRegistry.GetAssetsByPath(Package, AssetList, true);
+ if (AssetList.Num() == 0)
+ {
+ return false;
+ }
+
+ for (FAssetData Asset : AssetList)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ if (bOnlyRegisteredModTypes)
+ {
+ for (UClass * ModClass : RegisteredModTypes)
+ {
+ if (AssetClass->IsChildOf(ModClass))
+ {
+ Assets.Add(Asset);
+ break;
+ }
+ }
+ }
+ else
+ {
+ Assets.Add(Asset);
+ }
+ }
+ }
+ }
+ return Assets.Num() > 0;
+
+}
+
+void UUGCRegistry::ShowAllPossibleOverridesForClass(UClass * ModClass, TArray<UClass*> &Overrides)
+{
+ TArray<FAssetData> PackageAssets;
+ for (FName Package : UGCPackages)
+ {
+ GetAssetsFromPackage(Package, PackageAssets, true);
+ }
+
+ for (FAssetData Asset : PackageAssets)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass && AssetClass->IsChildOf(ModClass))
+ {
+ Overrides.Add(AssetClass);
+ }
+ }
+ }
+}
+
+UClass * UUGCRegistry::GetClassForAssetData(FAssetData Asset)
+{
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ return AssetClass;
+ }
+ }
+ return nullptr;
+}
+
+bool UUGCRegistry::ApplyAllModsInPackage(FName Package)
+{
+
+ bool success = false;
+ // Load up the AssetRegistry
+ FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
+ IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
+
+ TArray<FAssetData> AssetList;
+ AssetRegistry.GetAssetsByPath(Package, AssetList, true);
+ if (AssetList.Num() == 0)
+ {
+ return success;
+ }
+
+ for (FAssetData Asset : AssetList)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ for (UClass * ModClass : RegisteredModTypes)
+ {
+ if (AssetClass->IsChildOf(ModClass))
+ {
+ success = ApplyOverridesForModClass(AssetClass) || success;
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+bool UUGCRegistry::ApplyOverridesForModClass(UClass * ModClass)
+{
+ // Check Actors
+ AUGCBaseActor *UGCActor = Cast<AUGCBaseActor>(ModClass->GetDefaultObject());
+ if (UGCActor != nullptr)
+ {
+ for (UClass * ClassToOverride : UGCActor->ClassesToOverride)
+ {
+ if (ClassToOverride->IsChildOf(AUGCBaseActor::StaticClass()))
+ {
+ AssignOverrideForBaseClass(ClassToOverride, UGCActor->GetClass());
+ }
+ }
+ return true;
+ }
+
+ // Check Pawns & Characters
+ AUGCBasePawn *UGCPawn = Cast<AUGCBasePawn>(ModClass->GetDefaultObject());
+ if (UGCPawn != nullptr)
+ {
+ for (UClass * ClassToOverride : UGCPawn->ClassesToOverride)
+ {
+ if (ClassToOverride->IsChildOf(AUGCBasePawn::StaticClass()) ||
+ ClassToOverride->IsChildOf(AUGCBaseCharacter::StaticClass()))
+ {
+ AssignOverrideForBaseClass(ClassToOverride, UGCPawn->GetClass());
+ }
+ }
+ return true;
+ }
+
+ // Check Characters
+ AUGCBaseCharacter *UGCCharacter = Cast<AUGCBaseCharacter>(ModClass->GetDefaultObject());
+ if (UGCCharacter != nullptr)
+ {
+ for (UClass * ClassToOverride : UGCCharacter->ClassesToOverride)
+ {
+ if (ClassToOverride->IsChildOf(AUGCBasePawn::StaticClass()) ||
+ ClassToOverride->IsChildOf(AUGCBaseCharacter::StaticClass()))
+ {
+ AssignOverrideForBaseClass(ClassToOverride, UGCCharacter->GetClass());
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void UUGCRegistry::AssignOverrideForBaseClass(UClass * OriginClass, UClass * OverrideClass)
+{
+ // If already registered, Update Registration
+ for (FModOverridePairing &Pairing : RegisteredOverrides)
+ {
+ if (Pairing.Origin == OriginClass)
+ {
+ Pairing.Override = OverrideClass;
+
+ return;
+ }
+ }
+
+ // If not, make new
+ FModOverridePairing NewPairing;
+ NewPairing.Origin = OriginClass;
+ NewPairing.Override = OverrideClass;
+ RegisteredOverrides.Add(NewPairing);
+}
+
+bool UUGCRegistry::ClearOverrideForClass(UClass *OriginClass)
+{
+ // Find Pairing, remove From Array
+ for (int i = 0; i < RegisteredOverrides.Num(); i++)
+ {
+ FModOverridePairing & Pairing = RegisteredOverrides[i];
+ if (Pairing.Origin == OriginClass)
+ {
+ RegisteredOverrides.RemoveAt(i, 1, true);
+ return true;
+ }
+ }
+
+ // Returns False if there was no pairing to begin with
+ return false;
+}
+
+UClass * UUGCRegistry::GetOverrideForClass(UClass *OriginClass)
+{
+ for (FModOverridePairing &Pairing : RegisteredOverrides)
+ {
+ if (Pairing.Origin == OriginClass)
+ {
+ return Pairing.Override;
+ }
+ }
+ return OriginClass;
+} \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2bf9f51.TMP b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2bf9f51.TMP
new file mode 100644
index 0000000..a0c74da
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp~RF2bf9f51.TMP
@@ -0,0 +1,319 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "UGCRegistry.h"
+#include "UGCKit.h"
+
+
+
+bool UUGCRegistry::FindUGCPackages()
+{
+ // Now let's find all new root paths in the asset registry.
+ TArray<FString> RootPaths;
+ FPackageName::QueryRootContentPaths(RootPaths);
+
+ // Remove any plugins your game is shipping with, as well as engine and game roots. We only care about NEW paths.
+ RootPaths.Remove(TEXT("/Engine/"));
+ RootPaths.Remove(TEXT("/Game/"));
+ RootPaths.Remove(TEXT("/Paper2D/"));
+ RootPaths.Remove(TEXT("/UGCKit/"));
+
+ // Remove any other plugins you've defined in Blueprints
+ for (FName Package : PackageBlacklist)
+ {
+ RootPaths.Remove(Package.ToString());
+ }
+
+ if (RootPaths.Num() <= 0)
+ {
+ return false;
+ }
+
+ for (FString Path : RootPaths)
+ {
+ UGCPackages.Add(FName(*Path.LeftChop(1)));
+ }
+
+ return true;
+
+}
+
+bool UUGCRegistry::GetAssetsFromPackage(FName Package, TArray<FAssetData> &Assets, bool bOnlyRegisteredModTypes)
+{
+ // Load up the AssetRegistry
+ FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
+ IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
+
+ TArray<FAssetData> AssetList;
+ AssetRegistry.GetAssetsByPath(Package, AssetList, true);
+ if (AssetList.Num() == 0)
+ {
+ return false;
+ }
+
+ for (FAssetData Asset : AssetList)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ if (bOnlyRegisteredModTypes)
+ {
+ for (UClass * ModClass : RegisteredModTypes)
+ {
+ if (AssetClass->IsChildOf(ModClass))
+ {
+ Assets.Add(Asset);
+ break;
+ }
+ }
+ }
+ else
+ {
+ Assets.Add(Asset);
+ }
+ }
+ }
+ }
+ return Assets.Num() > 0;
+}
+
+bool UUGCRegistry::GetMapsFromPackage(FName Package, TArray<FName> &Maps)
+{
+ // Load up the AssetRegistry
+ FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
+ IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
+
+ FARFilter ARFilter;
+ TArray<FAssetData> AssetList;
+ // Add any old names to the list in case things haven't been resaved
+ ARFilter.ClassNames.Append(OldNames);
+ ARFilter.bRecursivePaths = true;
+ ARFilter.bIncludeOnlyOnDiskAssets = true;
+ ARFilter.bRecursiveClasses = true;
+
+ ////////////////////////////////////////
+ // Blueprint and CPP classes of our archetypes.
+ ARFilter.ClassNames.Add(UWorld::StaticClass()->GetFName());
+ ARFilter.PackagePaths.Add(Package);
+ AssetRegistry.GetAssets(ARFilter, AssetList);
+ AssetRegistry.GetAssetsByPath(Package, AssetList, true);
+ if (AssetList.Num() == 0)
+ {
+ return false;
+ }
+
+ for (FAssetData Asset : AssetList)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ if (bOnlyRegisteredModTypes)
+ {
+ for (UClass * ModClass : RegisteredModTypes)
+ {
+ if (AssetClass->IsChildOf(ModClass))
+ {
+ Assets.Add(Asset);
+ break;
+ }
+ }
+ }
+ else
+ {
+ Assets.Add(Asset);
+ }
+ }
+ }
+ }
+ return Assets.Num() > 0;
+}
+
+void UUGCRegistry::ShowAllPossibleOverridesForClass(UClass * ModClass, TArray<UClass*> &Overrides)
+{
+ TArray<FAssetData> PackageAssets;
+ for (FName Package : UGCPackages)
+ {
+ GetAssetsFromPackage(Package, PackageAssets, true);
+ }
+
+ for (FAssetData Asset : PackageAssets)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass && AssetClass->IsChildOf(ModClass))
+ {
+ Overrides.Add(AssetClass);
+ }
+ }
+ }
+}
+
+UClass * UUGCRegistry::GetClassForAssetData(FAssetData Asset)
+{
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ return AssetClass;
+ }
+ }
+ return nullptr;
+}
+
+bool UUGCRegistry::ApplyAllModsInPackage(FName Package)
+{
+
+ bool success = false;
+ // Load up the AssetRegistry
+ FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
+ IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
+
+ TArray<FAssetData> AssetList;
+ AssetRegistry.GetAssetsByPath(Package, AssetList, true);
+ if (AssetList.Num() == 0)
+ {
+ return success;
+ }
+
+ for (FAssetData Asset : AssetList)
+ {
+ const FString* ClassTextPath = Asset.TagsAndValues.Find("GeneratedClass");
+ if (ClassTextPath != NULL)
+ {
+ FString ClassPath = FPackageName::ExportTextPathToObjectPath(*ClassTextPath);
+ UClass* AssetClass = LoadObject<UClass>(NULL, *ClassPath);
+
+ // Check if it's a mod type
+ if (AssetClass)
+ {
+ for (UClass * ModClass : RegisteredModTypes)
+ {
+ if (AssetClass->IsChildOf(ModClass))
+ {
+ success = ApplyOverridesForModClass(AssetClass) || success;
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+bool UUGCRegistry::ApplyOverridesForModClass(UClass * ModClass)
+{
+ // Check Actors
+ AUGCBaseActor *UGCActor = Cast<AUGCBaseActor>(ModClass->GetDefaultObject());
+ if (UGCActor != nullptr)
+ {
+ for (UClass * ClassToOverride : UGCActor->ClassesToOverride)
+ {
+ if (ClassToOverride->IsChildOf(AUGCBaseActor::StaticClass()))
+ {
+ AssignOverrideForBaseClass(ClassToOverride, UGCActor->GetClass());
+ }
+ }
+ return true;
+ }
+
+ // Check Pawns
+ AUGCBasePawn *UGCPawn = Cast<AUGCBasePawn>(ModClass->GetDefaultObject());
+ if (UGCPawn != nullptr)
+ {
+ for (UClass * ClassToOverride : UGCPawn->ClassesToOverride)
+ {
+ // Character is a subclass of Pawn, so we're looking for either
+ if (ClassToOverride->IsChildOf(AUGCBasePawn::StaticClass()) ||
+ ClassToOverride->IsChildOf(AUGCBaseCharacter::StaticClass()))
+ {
+ AssignOverrideForBaseClass(ClassToOverride, UGCPawn->GetClass());
+ }
+ }
+ return true;
+ }
+
+ // Check Characters
+ AUGCBaseCharacter *UGCCharacter = Cast<AUGCBaseCharacter>(ModClass->GetDefaultObject());
+ if (UGCCharacter != nullptr)
+ {
+ for (UClass * ClassToOverride : UGCCharacter->ClassesToOverride)
+ {
+ // Pawn is a superclass of Character, so we're looking for either
+ if (ClassToOverride->IsChildOf(AUGCBasePawn::StaticClass()) ||
+ ClassToOverride->IsChildOf(AUGCBaseCharacter::StaticClass()))
+ {
+ AssignOverrideForBaseClass(ClassToOverride, UGCCharacter->GetClass());
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void UUGCRegistry::AssignOverrideForBaseClass(UClass * OriginClass, UClass * OverrideClass)
+{
+ // If already registered, Update Registration
+ for (FModOverridePairing &Pairing : RegisteredOverrides)
+ {
+ if (Pairing.Origin == OriginClass)
+ {
+ Pairing.Override = OverrideClass;
+ return;
+ }
+ }
+
+ // If not, make new
+ FModOverridePairing NewPairing;
+ NewPairing.Origin = OriginClass;
+ NewPairing.Override = OverrideClass;
+ RegisteredOverrides.Add(NewPairing);
+}
+
+bool UUGCRegistry::ClearOverrideForClass(UClass *OriginClass)
+{
+ // Find Pairing, remove From Array
+ for (int i = 0; i < RegisteredOverrides.Num(); i++)
+ {
+ FModOverridePairing & Pairing = RegisteredOverrides[i];
+ if (Pairing.Origin == OriginClass)
+ {
+ RegisteredOverrides.RemoveAt(i, 1, true);
+ return true;
+ }
+ }
+
+ // Returns False if there was no pairing to begin with
+ return false;
+}
+
+UClass * UUGCRegistry::GetOverrideForClass(UClass *OriginClass)
+{
+ for (FModOverridePairing &Pairing : RegisteredOverrides)
+ {
+ if (Pairing.Origin == OriginClass)
+ {
+ return Pairing.Override;
+ }
+ }
+ return OriginClass;
+} \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/MakeReplaceableActorComponent.h b/Plugins/SimpleUGC/Source/SimpleUGC/Public/MakeReplaceableActorComponent.h
new file mode 100644
index 0000000..4cc7289
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/MakeReplaceableActorComponent.h
@@ -0,0 +1,22 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Components/ActorComponent.h"
+#include "MakeReplaceableActorComponent.generated.h"
+
+UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
+class SIMPLEUGC_API UMakeReplaceableActorComponent : public UActorComponent
+{
+ GENERATED_BODY()
+
+public:
+ // Sets default values for this component's properties
+ UMakeReplaceableActorComponent();
+
+ // Only Classes of these Types can override this Actor. This is typically the type of actor you've places this component on or a safe superclass shared with an Override class.
+ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category ="SimpleUGC | Actor Replacement")
+ TSubclassOf<AActor> CompatibleReplacement;
+
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/ReplacementActorComponent.h b/Plugins/SimpleUGC/Source/SimpleUGC/Public/ReplacementActorComponent.h
new file mode 100644
index 0000000..f35429c
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/ReplacementActorComponent.h
@@ -0,0 +1,21 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Components/ActorComponent.h"
+#include "ReplacementActorComponent.generated.h"
+
+
+UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
+class SIMPLEUGC_API UReplacementActorComponent : public UActorComponent
+{
+ GENERATED_BODY()
+
+public:
+ UReplacementActorComponent();
+ // Add Classes you want to override here. Note: Classes added to this list MUST have a UMakeReplaceableActorComponent and This class's type be included in the component's ValidOverrideTypes
+ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SimpleUGC | Actor Replacement")
+ TArray<TSubclassOf<AActor>> ActorClassesToReplace;
+
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/SimpleUGC.h b/Plugins/SimpleUGC/Source/SimpleUGC/Public/SimpleUGC.h
new file mode 100644
index 0000000..f89e596
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/SimpleUGC.h
@@ -0,0 +1,10 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "Modules\ModuleManager.h"
+
+class FSimpleUGCModule : public IModuleInterface
+{
+public:
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBaseGameInstance.h b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBaseGameInstance.h
new file mode 100644
index 0000000..121886f
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBaseGameInstance.h
@@ -0,0 +1,25 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Engine/GameInstance.h"
+#include "UGCRegistry.h"
+#include "UGCBaseGameInstance.generated.h"
+
+/**
+ *
+ */
+UCLASS(BlueprintType)
+class SIMPLEUGC_API UUGCBaseGameInstance : public UGameInstance
+{
+ GENERATED_BODY()
+
+ public:
+ virtual void Init() override;
+
+ // The Registry that holds information about UGC and assigned class overrides
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC")
+ UUGCRegistry* UGCRegistry;
+
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBlueprintLibrary.h b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBlueprintLibrary.h
new file mode 100644
index 0000000..a0ed67c
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCBlueprintLibrary.h
@@ -0,0 +1,20 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "Kismet/BlueprintFunctionLibrary.h"
+#include "UGCRegistry.h"
+#include "UGCBlueprintLibrary.generated.h"
+
+
+UCLASS()
+class SIMPLEUGC_API UUGCBlueprintLibrary : public UBlueprintFunctionLibrary
+{
+
+ GENERATED_BODY()
+public:
+
+ // Gets the UGC Registry found in the GameInstance
+ UFUNCTION(BlueprintPure, Category = "SimpleUGC", meta = (WorldContext = "WorldContextObject"))
+ static UUGCRegistry * GetUGCRegistry(UObject* WorldContextObject);
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h
new file mode 100644
index 0000000..a2dfeea
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h
@@ -0,0 +1,98 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "AssetRegistryModule.h"
+#include "Engine.h"
+#include "SimpleUGC.h"
+#include "Engine/World.h"
+#include "Engine/BlendableInterface.h"
+#include "UGCRegistry.generated.h"
+
+USTRUCT(BlueprintType)
+struct FUGCPackage
+{
+ GENERATED_BODY()
+
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC")
+ FString PackagePath;
+
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC")
+ FString EngineVersion;
+
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC")
+ FString Author;
+
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC")
+ FString Description;
+
+ FUGCPackage()
+ {
+ PackagePath = "";
+ EngineVersion = "";
+ Author = "";
+ Description = "";
+ }
+};
+
+UCLASS(BlueprintType)
+class SIMPLEUGC_API UUGCRegistry : public UObject
+{
+ GENERATED_BODY()
+public:
+
+ // This is our list of UGC packages. Populated by FindUGCPackages()
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC")
+ TArray<FUGCPackage> UGCPackages;
+
+ // A pairing of Origins and Overrides. This is what the gameplay logic references when loading an effective class
+ UPROPERTY(BlueprintReadOnly, Category = "SimpleUGC|Actor Replacement")
+ TMap<TSubclassOf<AActor> /*Origin*/, TSubclassOf<AActor> /*Override*/> RegisteredOverrides;
+
+ // This populates UGCPackages based on what is found in UGC plugin files. If you're mounting new /Plugin paks at runtime. Expose this to Blueprints.
+ UFUNCTION(Blueprintcallable)
+ bool FindUGCPackages();
+
+ // General DLC Asset Access. Create Similar Methods For Getting Materials, Textures, etc.
+
+ // Returns All Classes in a UGC package.
+ UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SimpleUGC")
+ bool GetAllClassesInPackage(FUGCPackage Package, TArray<UClass*> &Classes);
+
+ // Returns All Maps in a UGC package.
+ UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SimpleUGC")
+ bool GetMapsInPackage(FUGCPackage Package, TArray<FName> &Maps);
+
+ // Actor Replacement Specific Calls
+
+ // Returns All Actor Classes In Package that have the ability to replace a a base class. Use this when you want to register only specific class overrides from a UGC package.
+ UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SimpleUGC|Actor Replacement")
+ bool GetActorClassesWithReplacementActorComponentsInPackage(FUGCPackage Package, TArray<TSubclassOf<AActor>> &ActorClasses);
+
+ // Applies entire package of Actor Replacements. This is common for applying an entire class-based "Mod."
+ UFUNCTION(BlueprintCallable, Category = "SimpleUGC|Actor Replacement")
+ bool ApplyAllOverridesInPackage(FUGCPackage Package);
+
+ // Applies an override for a specific Class. Find valid classes to use here by calling GetActorClassesWithReplacementActorComponentsInPackage
+ UFUNCTION(BlueprintCallable, Category = "SimpleUGC|Actor Replacement")
+ bool ApplyOverridesForActorClass(TSubclassOf<AActor> ActorClass);
+
+ // A manual override assignment. Not reccommended for mod packages, but useful for big UGC drops (100 UGuns pack, etc)
+ UFUNCTION(BlueprintCallable, Category = "SimpleUGC|Actor Replacement")
+ void RegisterOverrideForClass(TSubclassOf<AActor> ClassToOverride, TSubclassOf<AActor> OverrideClass);
+
+ // Used to clear the override from the registry. To clear all, loop through RegisterredOverrides, break the struct and run the Origin into this function.
+ UFUNCTION(BlueprintCallable, Category = "SimpleUGC|Actor Replacement")
+ void ClearOverrideForClass(TSubclassOf<AActor> ActorClass);
+
+ // Used in gameplay to look up what class is actually supposed to be spawned
+ UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SimpleUGC|Actor Replacement")
+ TSubclassOf<AActor> GetOverrideForActorClass(TSubclassOf<AActor> ActorClass);
+
+
+private:
+ FAssetRegistryModule* CachedAssetRegistryModule;
+ IAssetRegistry& GetAsstRegistry();
+
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h~RF2b28773.TMP b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h~RF2b28773.TMP
new file mode 100644
index 0000000..17cdab8
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/Public/UGCRegistry.h~RF2b28773.TMP
@@ -0,0 +1,106 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UGCKit.h"
+#include "Public/AssetRegistryModule.h"
+#include "Public/ARFilter.h"
+#include "UGCRegistry.generated.h"
+
+/**
+ *
+ */
+
+USTRUCT(BlueprintType)
+struct FModOverridePairing
+{
+ GENERATED_BODY()
+ UPROPERTY(BlueprintReadOnly, Category = "UGCKit|Modding")
+ UClass* Origin;
+
+ UPROPERTY(BlueprintReadOnly, Category = "UGCKit|Modding")
+ UClass* Override;
+
+ FModOverridePairing()
+ {
+ Origin = nullptr;
+ Override = nullptr;
+ }
+};
+
+
+UCLASS(BlueprintType)
+class UGCKIT_API UUGCRegistry : public UObject
+{
+ GENERATED_BODY()
+public:
+
+ // Init
+ UUGCRegistry()
+ {
+ RegisteredModTypes.Empty();
+ RegisteredModTypes.Add(AUGCBaseActor::StaticClass());
+ RegisteredModTypes.Add(AUGCBaseCharacter::StaticClass());
+ RegisteredModTypes.Add(AUGCBaseGameMode::StaticClass());
+ RegisteredModTypes.Add(AUGCBasePawn::StaticClass());
+ RegisteredModTypes.Add(AUGCBasePlayerController::StaticClass());
+ RegisteredModTypes.Add(AUGCBaseWorldSettings::StaticClass());
+
+ }
+
+ // PROPERTIES
+ UPROPERTY(BlueprintReadOnly, Category = "UGCKit")
+ TArray<FName> UGCPackages;
+
+ UPROPERTY(BlueprintReadWrite, Category = "UGCKit")
+ TArray<FName> PackageBlacklist;
+
+ UPROPERTY(BlueprintReadOnly, Category = "UGCKit|Modding")
+ TArray <UClass*> RegisteredModTypes;
+
+ UPROPERTY(BlueprintReadOnly, Category = "UGCKit|Modding")
+ TArray <UClass*> PossibleModOverrides;
+
+ UPROPERTY(BlueprintReadOnly, Category = "UGCKit|Modding")
+ TArray <FModOverridePairing> RegisteredOverrides;
+
+ // This populates UGCPackages based on what is found in mounted pak files. If you're mounting new /Plugin paks at runtime, call this again to update UGCPacakges
+ UFUNCTION(BlueprintCallable, Category = "UGCKit")
+ bool FindUGCPackages();
+
+ // For querying assets in a specific package.
+ UFUNCTION(BlueprintCallable, Category = "UGCKit")
+ bool GetAssetsFromPackage(FName Package, TArray<FAssetData> &Assets, bool bOnlyRegisteredModTypes);
+
+ // Helper for Blueprints to use cached AssetData info to get an actual UClass. Mainly used in conjunction with ApplyOverrideForModClass
+ UFUNCTION(BlueprintCallable, Category = "UGCKit")
+ UClass * GetClassForAssetData(FAssetData Asset);
+
+ // Applies entire package of mods
+ UFUNCTION(BlueprintCallable, Category = "UGCKit|Modding")
+ bool ApplyAllModsInPackage(FName Package);
+
+ // Assigns overrides for just one mod class.
+ UFUNCTION(BlueprintCallable, Category = "UGCKit|Modding")
+ bool ApplyOverridesForModClass(UClass * ModClass);
+
+ // A manual override assignment. Not reccommended for mod packages, but useful for bug UGC drops (100 gun pack, etc)
+ UFUNCTION(BlueprintCallable, Category = "UGCKit|Modding")
+ void AssignOverrideForBaseClass(UClass * OriginClass, UClass * OverrideClass);
+
+ // Usually used with the above, this looks at all UGC Packages and provides a list of possible overrides (Give me all new guns)
+ UFUNCTION(BlueprintCallable, Category = "UGCKit|Modding")
+ void ShowAllPossibleOverridesForClass(UClass * ModClass, TArray<UClass*> &Overrides);
+
+ // Used to clear the override from the registry. To clear all, loop through RegisterredOverrides, break the struct and run the Origin into this function.
+ UFUNCTION(BlueprintCallable, Category = "UGCKit|Modding")
+ bool ClearOverrideForClass(UClass *OriginClass);
+
+ // Used in gameplay to look up what class is actually supposed to be spawned
+ UFUNCTION(BlueprintCallable, Category = "UGCKit|Modding")
+ UClass * GetOverrideForClass(UClass *OriginClass);
+
+
+
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGC/SimpleUGC.Build.cs b/Plugins/SimpleUGC/Source/SimpleUGC/SimpleUGC.Build.cs
new file mode 100644
index 0000000..60621c3
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGC/SimpleUGC.Build.cs
@@ -0,0 +1,59 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+using UnrealBuildTool;
+
+public class SimpleUGC : ModuleRules
+{
+ public SimpleUGC(ReadOnlyTargetRules Target) : base(Target)
+ {
+ PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
+
+ PublicIncludePaths.AddRange(
+ new string[] {
+
+ // ... add public include paths required here ...
+ }
+ );
+
+
+ PrivateIncludePaths.AddRange(
+ new string[] {
+
+ // ... add other private include paths required here ...
+ }
+ );
+
+
+ PublicDependencyModuleNames.AddRange(
+ new string[]
+ {
+ "Core",
+ "AssetRegistry"
+
+ // ... add other public dependencies that you statically link with here ...
+ }
+ );
+
+
+ PrivateDependencyModuleNames.AddRange(
+ new string[]
+ {
+ "CoreUObject",
+ "Engine",
+ "Slate",
+ "SlateCore",
+ "AssetRegistry",
+ "Projects",
+ // ... add private dependencies that you statically link with here ...
+ }
+ );
+
+
+ DynamicallyLoadedModuleNames.AddRange(
+ new string[]
+ {
+ // ... add any modules that your module loads dynamically here ...
+ }
+ );
+ }
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCCreator.cpp b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCCreator.cpp
new file mode 100644
index 0000000..d7403a9
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCCreator.cpp
@@ -0,0 +1,65 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+//#include "SimpleUGCEditorPrivatePCH.h"
+#include "SimpleUGCCreator.h"
+
+#include "SimpleUGCPluginWizardDefinition.h"
+#include "Widgets/Docking/SDockTab.h"
+
+// This depends on the Plugin Browser module to work correctly...
+#include "IPluginBrowser.h"
+
+
+
+#define LOCTEXT_NAMESPACE "FSimpleUGCCreator"
+
+const FName FSimpleUGCCreator::SimpleUGCEditorPluginCreatorName("SimpleUGCPluginCreator");
+
+FSimpleUGCCreator::FSimpleUGCCreator()
+{
+ RegisterTabSpawner();
+}
+
+FSimpleUGCCreator::~FSimpleUGCCreator()
+{
+ UnregisterTabSpawner();
+}
+
+void FSimpleUGCCreator::OpenNewPluginWizard(bool bSuppressErrors) const
+{
+ if (IPluginBrowser::IsAvailable())
+ {
+ FGlobalTabmanager::Get()->InvokeTab(SimpleUGCEditorPluginCreatorName);
+ }
+ else if (!bSuppressErrors)
+ {
+ FMessageDialog::Open(EAppMsgType::Ok,
+ LOCTEXT("PluginBrowserDisabled", "Creating a game mod requires the use of the Plugin Browser, but it is currently disabled."));
+ }
+}
+
+void FSimpleUGCCreator::RegisterTabSpawner()
+{
+ FTabSpawnerEntry& Spawner = FGlobalTabmanager::Get()->RegisterNomadTabSpawner(SimpleUGCEditorPluginCreatorName,
+ FOnSpawnTab::CreateRaw(this, &FSimpleUGCCreator::HandleSpawnPluginTab));
+
+ // Set a default size for this tab
+ FVector2D DefaultSize(800.0f, 500.0f);
+ FTabManager::RegisterDefaultTabWindowSize(SimpleUGCEditorPluginCreatorName, DefaultSize);
+
+ Spawner.SetDisplayName(LOCTEXT("NewUGCTabHeader", "Create New UGC Package"));
+ Spawner.SetMenuType(ETabSpawnerMenuType::Hidden);
+}
+
+void FSimpleUGCCreator::UnregisterTabSpawner()
+{
+ FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(SimpleUGCEditorPluginCreatorName);
+}
+
+TSharedRef<SDockTab> FSimpleUGCCreator::HandleSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
+{
+ check(IPluginBrowser::IsAvailable());
+ return IPluginBrowser::Get().SpawnPluginCreatorTab(SpawnTabArgs, MakeShared<FSimpleUGCPluginWizardDefinition>());
+}
+
+#undef LOCTEXT_NAMESPACE \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditor.cpp b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditor.cpp
new file mode 100644
index 0000000..ce43dde
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditor.cpp
@@ -0,0 +1,130 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "SimpleUGCEditor.h"
+#include "SimpleUGCEditorStyle.h"
+#include "SimpleUGCEditorCommands.h"
+#include "SimpleUGCCreator.h"
+#include "Misc/MessageDialog.h"
+#include "Framework/MultiBox/MultiBoxBuilder.h"
+
+#include "LevelEditor.h"
+
+static const FName SimpleUGCEditorTabName("SimpleUGCEditor");
+
+#define LOCTEXT_NAMESPACE "FSimpleUGCEditorModule"
+
+void FSimpleUGCEditorModule::StartupModule()
+{
+ // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
+
+ UGCCreator = MakeShared<FSimpleUGCCreator>();
+ UGCPackager = MakeShared<FSimpleUGCPackager>();
+
+ FSimpleUGCEditorStyle::Initialize();
+ FSimpleUGCEditorStyle::ReloadTextures();
+
+ FSimpleUGCEditorCommands::Register();
+
+ PluginCommands = MakeShareable(new FUICommandList);
+
+ PluginCommands->MapAction(
+ FSimpleUGCEditorCommands::Get().CreateUGCAction,
+ FExecuteAction::CreateRaw(this, &FSimpleUGCEditorModule::CreateUGCButtonClicked),
+ FCanExecuteAction()
+ );
+
+ FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
+ // Add commands
+ {
+ FName MenuSection = "FileProject";
+ FName ToolbarSection = "Misc";
+
+ // Add creator button to the menu
+ {
+ TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
+ MenuExtender->AddMenuExtension(MenuSection, EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FSimpleUGCEditorModule::AddUGCCreatorMenuExtension));
+
+ LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
+ }
+
+ // Add creator button to the toolbar
+ {
+ TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
+ ToolbarExtender->AddToolBarExtension(ToolbarSection, EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FSimpleUGCEditorModule::AddUGCCreatorToolbarExtension));
+
+ LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
+ }
+
+ // Add packager button to the menu
+ {
+ TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
+ MenuExtender->AddMenuExtension(MenuSection, EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FSimpleUGCEditorModule::AddUGCPackagerMenuExtension));
+
+ LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
+ }
+
+ // Add packager button to the toolbar
+ {
+ TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
+ ToolbarExtender->AddToolBarExtension(ToolbarSection, EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FSimpleUGCEditorModule::AddUGCPackagerToolbarExtension));
+
+ LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
+ }
+ }
+}
+
+void FSimpleUGCEditorModule::ShutdownModule()
+{
+ // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
+ // we call this function before unloading the module.
+ FSimpleUGCEditorStyle::Shutdown();
+
+ FSimpleUGCEditorCommands::Unregister();
+
+}
+
+void FSimpleUGCEditorModule::CreateUGCButtonClicked()
+{
+ if (UGCCreator.IsValid())
+ {
+ UGCCreator->OpenNewPluginWizard();
+ }
+}
+
+void FSimpleUGCEditorModule::AddUGCCreatorMenuExtension(FMenuBuilder& Builder)
+{
+ Builder.AddMenuEntry(FSimpleUGCEditorCommands::Get().CreateUGCAction);
+}
+
+void FSimpleUGCEditorModule::AddUGCCreatorToolbarExtension(FToolBarBuilder& Builder)
+{
+ Builder.AddToolBarButton(FSimpleUGCEditorCommands::Get().CreateUGCAction);
+}
+
+void FSimpleUGCEditorModule::AddUGCPackagerMenuExtension(FMenuBuilder& Builder)
+{
+ FSimpleUGCPackager* Packager = UGCPackager.Get();
+
+ Builder.AddSubMenu(LOCTEXT("PackageUGCMenu_Label", "Package UGC"),
+ LOCTEXT("PackageUGCMenu_Tooltip", "Share and distribute UGC"),
+ FNewMenuDelegate::CreateRaw(Packager, &FSimpleUGCPackager::GeneratePackagerMenuContent),
+ false,
+ FSlateIcon(FSimpleUGCEditorStyle::GetStyleSetName(), "SimpleUGCEditor.PackageUGCAction")
+ );
+}
+
+void FSimpleUGCEditorModule::AddUGCPackagerToolbarExtension(FToolBarBuilder& Builder)
+{
+ FSimpleUGCPackager* Packager = UGCPackager.Get();
+
+ Builder.AddComboButton(FUIAction(),
+ FOnGetContent::CreateSP(Packager, &FSimpleUGCPackager::GeneratePackagerComboButtonContent),
+ LOCTEXT("PackageUGC_Label", "Package UGC"),
+ LOCTEXT("PackageUGC_Tooltip", "Share and distribute UGC"),
+ FSlateIcon(FSimpleUGCEditorStyle::GetStyleSetName(), "SimpleUGCEditor.PackageUGCAction")
+ );
+}
+
+#undef LOCTEXT_NAMESPACE
+
+IMPLEMENT_MODULE(FSimpleUGCEditorModule, SimpleUGCEditor)
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorCommands.cpp b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorCommands.cpp
new file mode 100644
index 0000000..846c5a3
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorCommands.cpp
@@ -0,0 +1,51 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "SimpleUGCEditorCommands.h"
+#include "Interfaces/IPluginManager.h"
+
+#define LOCTEXT_NAMESPACE "FSimpleUGCEditorModule"
+
+void FSimpleUGCEditorCommands::RegisterCommands()
+{
+ UI_COMMAND(CreateUGCAction, "Create UGC", "Create a new UGC package in a mod plugin", EUserInterfaceActionType::Button, FInputGesture());
+ UI_COMMAND(PackageUGCAction, "Package UGC", "Share and distribute your UGC", EUserInterfaceActionType::Button, FInputGesture());
+}
+
+TArray<TSharedPtr<FUICommandInfo>> FSimpleUGCEditorCommands::RegisterUGCCommands(const TArray<TSharedRef<class IPlugin>>& UGCList) const
+{
+ TArray<TSharedPtr<FUICommandInfo>> AvailableUGCActions;
+ AvailableUGCActions.Reserve(UGCList.Num());
+
+ FSimpleUGCEditorCommands* MutableThis = const_cast<FSimpleUGCEditorCommands*>(this);
+
+ for (int32 Index = 0; Index < UGCList.Num(); ++Index)
+ {
+ AvailableUGCActions.Add(TSharedPtr<FUICommandInfo>());
+ TSharedRef<IPlugin> UGC = UGCList[Index];
+
+ FString CommandName = "UGCEditorUGC_" + UGC->GetName();
+
+ FUICommandInfo::MakeCommandInfo(MutableThis->AsShared(),
+ AvailableUGCActions[Index],
+ FName(*CommandName),
+ FText::FromString(UGC->GetName()),
+ FText::FromString(UGC->GetBaseDir()),
+ FSlateIcon(),
+ EUserInterfaceActionType::Button,
+ FInputGesture());
+ }
+
+ return AvailableUGCActions;
+}
+
+void FSimpleUGCEditorCommands::UnregisterUGCCommands(TArray<TSharedPtr<FUICommandInfo>>& UICommands) const
+{
+ FSimpleUGCEditorCommands* MutableThis = const_cast<FSimpleUGCEditorCommands*>(this);
+
+ for (TSharedPtr<FUICommandInfo> Command : UICommands)
+ {
+ FUICommandInfo::UnregisterCommandInfo(MutableThis->AsShared(), Command.ToSharedRef());
+ }
+}
+
+#undef LOCTEXT_NAMESPACE \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorStyle.cpp b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorStyle.cpp
new file mode 100644
index 0000000..309261a
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCEditorStyle.cpp
@@ -0,0 +1,72 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "SimpleUGCEditorStyle.h"
+#include "SimpleUGCEditor.h"
+#include "Framework/Application/SlateApplication.h"
+#include "Styling/SlateStyleRegistry.h"
+#include "Slate/SlateGameResources.h"
+#include "Interfaces/IPluginManager.h"
+
+TSharedPtr< FSlateStyleSet > FSimpleUGCEditorStyle::StyleInstance = NULL;
+
+void FSimpleUGCEditorStyle::Initialize()
+{
+ if (!StyleInstance.IsValid())
+ {
+ StyleInstance = Create();
+ FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
+ }
+}
+
+void FSimpleUGCEditorStyle::Shutdown()
+{
+ FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
+ ensure(StyleInstance.IsUnique());
+ StyleInstance.Reset();
+}
+
+FName FSimpleUGCEditorStyle::GetStyleSetName()
+{
+ static FName StyleSetName(TEXT("SimpleUGCEditorStyle"));
+ return StyleSetName;
+}
+
+#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define TTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".ttf") ), __VA_ARGS__ )
+#define OTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".otf") ), __VA_ARGS__ )
+
+const FVector2D Icon16x16(16.0f, 16.0f);
+const FVector2D Icon20x20(20.0f, 20.0f);
+const FVector2D Icon40x40(40.0f, 40.0f);
+
+TSharedRef< FSlateStyleSet > FSimpleUGCEditorStyle::Create()
+{
+ TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("SimpleUGCEditorStyle"));
+ Style->SetContentRoot(IPluginManager::Get().FindPlugin("SimpleUGC")->GetBaseDir() / TEXT("Resources"));
+
+ Style->Set("SimpleUGCEditor.PackageUGCAction", new IMAGE_BRUSH(TEXT("PackageUGC_64x"), Icon40x40));
+ Style->Set("SimpleUGCEditor.CreateUGCAction", new IMAGE_BRUSH(TEXT("CreateUGC_64x"), Icon40x40));
+
+ return Style;
+}
+
+#undef IMAGE_BRUSH
+#undef BOX_BRUSH
+#undef BORDER_BRUSH
+#undef TTF_FONT
+#undef OTF_FONT
+
+void FSimpleUGCEditorStyle::ReloadTextures()
+{
+ if (FSlateApplication::IsInitialized())
+ {
+ FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
+ }
+}
+
+const ISlateStyle& FSimpleUGCEditorStyle::Get()
+{
+ return *StyleInstance;
+}
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPackager.cpp b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPackager.cpp
new file mode 100644
index 0000000..c7bc2db
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPackager.cpp
@@ -0,0 +1,205 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "SimpleUGCPackager.h"
+#include "SimpleUGCEditor.h"
+#include "SimpleUGCEditorCommands.h"
+#include "SimpleUGCEditorStyle.h"
+#include "Editor.h"
+#include "Widgets/SWindow.h"
+#include "Widgets/SWidget.h"
+#include "Interfaces/IPluginManager.h"
+#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
+#include "Editor/UATHelper/Public/IUATHelperModule.h"
+#include "Editor/MainFrame/Public/Interfaces/IMainFrameModule.h"
+
+#include "FileHelpers.h"
+#include "Misc/PackageName.h"
+
+#define LOCTEXT_NAMESPACE "SimpleUGCPackager"
+
+FSimpleUGCPackager::FSimpleUGCPackager()
+{
+}
+
+FSimpleUGCPackager::~FSimpleUGCPackager()
+{
+}
+
+void FSimpleUGCPackager::OpenPluginPackager(TSharedRef<IPlugin> Plugin)
+{
+ IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
+
+ FString DefaultDirectory = FPaths::ConvertRelativePathToFull(Plugin->GetBaseDir());
+ FString OutputDirectory;
+
+ // Prompt the user to save all dirty packages. We'll ensure that if any packages from the mod that the user wants to
+ // package are dirty that they will not be able to save them.
+
+ if (!IsAllContentSaved(Plugin))
+ {
+ FEditorFileUtils::SaveDirtyPackages( true, true, true);
+ }
+
+ if (IsAllContentSaved(Plugin))
+ {
+ void* ParentWindowWindowHandle = nullptr;
+ IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
+ const TSharedPtr<SWindow>& MainFrameParentWindow = MainFrameModule.GetParentWindow();
+ if (MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid())
+ {
+ ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle();
+ }
+
+ if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("SelectOutputFolderTitle", "Select UGC output directory:").ToString(), DefaultDirectory, OutputDirectory))
+ {
+ PackagePlugin(Plugin, OutputDirectory);
+ }
+ }
+ else
+ {
+ FText PackageModError = FText::Format(LOCTEXT("PackageUGCError_UnsavedContent", "You must save all assets in {0} before you can share it."),
+ FText::FromString(Plugin->GetName()));
+
+ FMessageDialog::Open(EAppMsgType::Ok, PackageModError);
+ }
+}
+
+bool FSimpleUGCPackager::IsAllContentSaved(TSharedRef<IPlugin> Plugin)
+{
+ bool bAllContentSaved = true;
+
+ TArray<UPackage*> UnsavedPackages;
+ FEditorFileUtils::GetDirtyContentPackages(UnsavedPackages);
+ FEditorFileUtils::GetDirtyWorldPackages(UnsavedPackages);
+
+ if (UnsavedPackages.Num() > 0)
+ {
+ FString PluginBaseDir = Plugin->GetBaseDir();
+
+ for (UPackage* Package : UnsavedPackages)
+ {
+ FString PackageFilename;
+ if (FPackageName::TryConvertLongPackageNameToFilename(Package->GetName(), PackageFilename))
+ {
+ if (PackageFilename.Find(PluginBaseDir) == 0)
+ {
+ bAllContentSaved = false;
+ break;
+ }
+ }
+ }
+ }
+
+ return bAllContentSaved;
+}
+
+void FSimpleUGCPackager::PackagePlugin(TSharedRef<class IPlugin> Plugin, const FString& OutputDirectory)
+{
+#if PLATFORM_WINDOWS
+ FText PlatformName = LOCTEXT("PlatformName_Windows", "Windows");
+#elif PLATFORM_MAC
+ FText PlatformName = LOCTEXT("PlatformName_Mac", "Mac");
+#elif PLATFORM_LINUX
+ FText PlatformName = LOCTEXT("PlatformName_Linux", "Linux");
+#else
+ FText PlatformName = LOCTEXT("PlatformName_Desktop", "Desktop");
+#endif
+
+ // Hard coded here for simplicity. You will probably want to read this from an ini file
+ FString ReleaseVersion = TEXT("UGCExampleGame_v1");
+
+ FString CommandLine = FString::Printf(TEXT("PackageUGC -Project=\"%s\" -PluginPath=\"%s\" -basedonreleaseversion=\"%s\" -StagingDirectory=\"%s\" -nocompile"),
+ *FPaths::ConvertRelativePathToFull(FPaths::GetProjectFilePath()),
+ *FPaths::ConvertRelativePathToFull(Plugin->GetDescriptorFileName()),
+ *ReleaseVersion,
+ *OutputDirectory);
+
+ FText PackagingText = FText::Format(LOCTEXT("SimpleUGCEditor_PackagePluginTaskName", "Packaging {0}"), FText::FromString(Plugin->GetName()));
+
+ FString FriendlyName = Plugin->GetDescriptor().FriendlyName;
+ IUATHelperModule::Get().CreateUatTask(CommandLine, PlatformName, PackagingText,
+ PackagingText, FSimpleUGCEditorStyle::Get().GetBrush(TEXT("SimpleUGCEditor.PackageUGCAction")),
+ [ReleaseVersion, PlatformName, FriendlyName](FString TaskResult, double TimeSec) {});
+}
+
+void FSimpleUGCPackager::FindAvailableGameMods(TArray<TSharedRef<IPlugin>>& OutAvailableGameMods)
+{
+ OutAvailableGameMods.Empty();
+
+ // Find available game mods from the list of discovered plugins
+
+ for (TSharedRef<IPlugin> Plugin : IPluginManager::Get().GetDiscoveredPlugins())
+ {
+ // All game project plugins that are marked as mods are valid
+ if (Plugin->GetLoadedFrom() == EPluginLoadedFrom::Project && Plugin->GetType() == EPluginType::Mod)
+ {
+ UE_LOG(LogTemp, Display, TEXT("Adding %s"), *Plugin->GetName());
+ OutAvailableGameMods.AddUnique(Plugin);
+ }
+ }
+}
+
+void FSimpleUGCPackager::GeneratePackagerMenuContent_Internal(class FMenuBuilder& MenuBuilder, const TArray<TSharedPtr<FUICommandInfo>>& Commands)
+{
+ for (TSharedPtr<FUICommandInfo> Command : Commands)
+ {
+ MenuBuilder.AddMenuEntry(Command, NAME_None, TAttribute<FText>(), TAttribute<FText>(), FSlateIcon(FSimpleUGCEditorStyle::GetStyleSetName(), "SimpleUGCEditor.Folder"));
+ }
+}
+
+void FSimpleUGCPackager::GeneratePackagerMenuContent(class FMenuBuilder& MenuBuilder)
+{
+ TArray<TSharedRef<IPlugin>> AvailableGameMods;
+ FindAvailableGameMods(AvailableGameMods);
+
+ TArray<TSharedPtr<FUICommandInfo>> Commands;
+
+ GeneratePackagerMenuContent_Internal(MenuBuilder, UGCCommands);
+}
+
+TSharedRef<SWidget> FSimpleUGCPackager::GeneratePackagerComboButtonContent()
+{
+ // Regenerate the game mod commands
+ TArray<TSharedRef<IPlugin>> AvailableGameMods;
+ FindAvailableGameMods(AvailableGameMods);
+
+ GetAvailableUGCCommands(AvailableGameMods);
+
+ // Regenerate the action list
+ TSharedPtr<FUICommandList> GameModActionsList = MakeShareable(new FUICommandList);
+
+ for (int32 Index = 0; Index < UGCCommands.Num(); ++Index)
+ {
+ GameModActionsList->MapAction(
+ UGCCommands[Index],
+ FExecuteAction::CreateRaw(this, &FSimpleUGCPackager::OpenPluginPackager, AvailableGameMods[Index]),
+ FCanExecuteAction()
+ );
+ }
+
+ // Show the drop down menu
+ const bool bShouldCloseWindowAfterMenuSelection = true;
+ FMenuBuilder MenuBuilder(bShouldCloseWindowAfterMenuSelection, GameModActionsList);
+
+ MenuBuilder.BeginSection(NAME_None, LOCTEXT("PackageUGC", "Share..."));
+ {
+ GeneratePackagerMenuContent_Internal(MenuBuilder, UGCCommands);
+ }
+ MenuBuilder.EndSection();
+
+ return MenuBuilder.MakeWidget();
+}
+
+void FSimpleUGCPackager::GetAvailableUGCCommands(const TArray<TSharedRef<IPlugin>>& AvailableUGC)
+{
+ if (UGCCommands.Num() > 0)
+ {
+ // Unregister UI Commands
+ FSimpleUGCEditorCommands::Get().UnregisterUGCCommands(UGCCommands);
+ }
+ UGCCommands.Empty(AvailableUGC.Num());
+
+ UGCCommands = FSimpleUGCEditorCommands::Get().RegisterUGCCommands(AvailableUGC);
+}
+
+#undef LOCTEXT_NAMESPACE \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPluginWizardDefinition.cpp b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPluginWizardDefinition.cpp
new file mode 100644
index 0000000..53abeb4
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Private/SimpleUGCPluginWizardDefinition.cpp
@@ -0,0 +1,214 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "SimpleUGCPluginWizardDefinition.h"
+#include "ContentBrowserModule.h"
+#include "EngineAnalytics.h"
+#include "Interfaces/IPluginManager.h"
+#include "IContentBrowserSingleton.h"
+#include "Algo/Transform.h"
+#include "SlateBasics.h"
+#include "SourceCodeNavigation.h"
+
+#define LOCTEXT_NAMESPACE "SimpleUGCPluginWizard"
+
+FSimpleUGCPluginWizardDefinition::FSimpleUGCPluginWizardDefinition()
+{
+ PluginBaseDir = IPluginManager::Get().FindPlugin(TEXT("SimpleUGC"))->GetBaseDir();
+ // Find the Content Only Template that ships with the plugin.
+ // Download the Robo Recall Mod Kit and check the Plugins/OdinEditor code for how to build and use your own UGC templates from your game content
+ BackingTemplate = MakeShareable(new FPluginTemplateDescription(FText(), FText(), TEXT("BaseTemplate"), true, EHostType::Runtime));
+ BackingTemplatePath = PluginBaseDir / TEXT("Templates") / BackingTemplate->OnDiskPath;
+}
+
+const TArray<TSharedRef<FPluginTemplateDescription>>& FSimpleUGCPluginWizardDefinition::GetTemplatesSource() const
+{
+ return TemplateDefinitions;
+}
+
+void FSimpleUGCPluginWizardDefinition::OnTemplateSelectionChanged(TArray<TSharedRef<FPluginTemplateDescription>> InSelectedItems, ESelectInfo::Type SelectInfo)
+{
+ SelectedTemplates = InSelectedItems;
+}
+
+TArray<TSharedPtr<FPluginTemplateDescription>> FSimpleUGCPluginWizardDefinition::GetSelectedTemplates() const
+{
+ TArray<TSharedPtr<FPluginTemplateDescription>> SelectedTemplatePtrs;
+
+ for (TSharedRef<FPluginTemplateDescription> Ref : SelectedTemplates)
+ {
+ SelectedTemplatePtrs.Add(Ref);
+ }
+
+ return SelectedTemplatePtrs;
+}
+
+void FSimpleUGCPluginWizardDefinition::ClearTemplateSelection()
+{
+ SelectedTemplates.Empty();
+}
+
+bool FSimpleUGCPluginWizardDefinition::HasValidTemplateSelection() const
+{
+ // A mod should be created even if no templates are actually selected
+ return true;
+}
+
+bool FSimpleUGCPluginWizardDefinition::CanContainContent() const
+{
+ bool bHasContent = SelectedTemplates.Num() == 0; // if no templates are selected, by default it is a content mod
+
+ if (!bHasContent)
+ {
+ for (TSharedPtr<FPluginTemplateDescription> Template : SelectedTemplates)
+ {
+ // If at least one module can contain content, it's a content mod. Otherwise, it's a pure code mod.
+ if (Template->bCanContainContent)
+ {
+ bHasContent = true;
+ break;
+ }
+ }
+ }
+
+ return bHasContent;
+}
+
+bool FSimpleUGCPluginWizardDefinition::HasModules() const
+{
+ bool bHasModules = false;
+
+ for (TSharedPtr<FPluginTemplateDescription> Template : SelectedTemplates)
+ {
+ if (FPaths::DirectoryExists(PluginBaseDir / TEXT("Templates") / Template->OnDiskPath / TEXT("Source")))
+ {
+ bHasModules = true;
+ break;
+ }
+ }
+
+ return bHasModules;
+}
+
+bool FSimpleUGCPluginWizardDefinition::IsMod() const
+{
+ return true;
+}
+
+void FSimpleUGCPluginWizardDefinition::OnShowOnStartupCheckboxChanged(ECheckBoxState CheckBoxState)
+{
+}
+
+ECheckBoxState FSimpleUGCPluginWizardDefinition::GetShowOnStartupCheckBoxState() const
+{
+ return ECheckBoxState();
+}
+
+FText FSimpleUGCPluginWizardDefinition::GetInstructions() const
+{
+ return LOCTEXT("CreateNewUGCPanel", "Give your new UGC package a name and Click 'Create Mod' to make a new content only UGC package.");
+}
+
+TSharedPtr<SWidget> FSimpleUGCPluginWizardDefinition::GetCustomHeaderWidget()
+{
+ if ( !CustomHeaderWidget.IsValid() )
+ {
+ FString IconPath;
+ GetPluginIconPath(IconPath);
+
+ const FName BrushName(*IconPath);
+ const FIntPoint Size = FSlateApplication::Get().GetRenderer()->GenerateDynamicImageResource(BrushName);
+ if ((Size.X > 0) && (Size.Y > 0))
+ {
+ IconBrush = MakeShareable(new FSlateDynamicImageBrush(BrushName, FVector2D(Size.X, Size.Y)));
+ }
+
+ CustomHeaderWidget = SNew(SHorizontalBox)
+ // Header image
+ + SHorizontalBox::Slot()
+ .AutoWidth()
+ .Padding(4.0f)
+ [
+ SNew(SBox)
+ .WidthOverride(80.0f)
+ .HeightOverride(80.0f)
+ [
+ SNew(SImage)
+ .Image(IconBrush.IsValid() ? IconBrush.Get() : nullptr)
+ ]
+ ];
+ }
+
+ return CustomHeaderWidget;
+}
+
+bool FSimpleUGCPluginWizardDefinition::GetPluginIconPath(FString& OutIconPath) const
+{
+ // Replace this file with your own 128x128 image if desired.
+ OutIconPath = BackingTemplatePath / TEXT("Resources/Icon128.png");
+ return false;
+}
+
+bool FSimpleUGCPluginWizardDefinition::GetTemplateIconPath(TSharedRef<FPluginTemplateDescription> InTemplate, FString& OutIconPath) const
+{
+ FString TemplateName = InTemplate->Name.ToString();
+
+ OutIconPath = PluginBaseDir / TEXT("Resources");
+
+ if (TemplateToIconMap.Contains(TemplateName))
+ {
+ OutIconPath /= TemplateToIconMap[TemplateName];
+ }
+ else
+ {
+ // Couldn't find a suitable icon to use for this template, so use the default one instead
+ OutIconPath /= TEXT("Icon128.png");
+ }
+
+ return false;
+}
+
+FString FSimpleUGCPluginWizardDefinition::GetPluginFolderPath() const
+{
+ return BackingTemplatePath;
+}
+
+EHostType::Type FSimpleUGCPluginWizardDefinition::GetPluginModuleDescriptor() const
+{
+ return BackingTemplate->ModuleDescriptorType;
+}
+
+ELoadingPhase::Type FSimpleUGCPluginWizardDefinition::GetPluginLoadingPhase() const
+{
+ return BackingTemplate->LoadingPhase;
+}
+
+TArray<FString> FSimpleUGCPluginWizardDefinition::GetFoldersForSelection() const
+{
+ TArray<FString> SelectedFolders;
+ SelectedFolders.Add(BackingTemplatePath); // This will always be a part of the mod plugin
+
+ for (TSharedPtr<FPluginTemplateDescription> Template : SelectedTemplates)
+ {
+ SelectedFolders.AddUnique(PluginBaseDir / TEXT("Templates") / Template->OnDiskPath);
+ }
+
+ return SelectedFolders;
+}
+
+void FSimpleUGCPluginWizardDefinition::PluginCreated(const FString& PluginName, bool bWasSuccessful) const
+{
+ // Override Category to UGC
+ if (bWasSuccessful)
+ {
+ TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(PluginName);
+ if (Plugin != nullptr)
+ {
+ FPluginDescriptor Desc = Plugin->GetDescriptor();
+ Desc.Category = "UGC";
+ FText UpdateFailureText;
+ Plugin->UpdateDescriptor(Desc, UpdateFailureText);
+ }
+ }
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCCreator.h b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCCreator.h
new file mode 100644
index 0000000..43e41ea
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCCreator.h
@@ -0,0 +1,33 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+class FSimpleUGCPluginWizardDefinition;
+class SDockTab;
+
+class FSimpleUGCCreator : public TSharedFromThis<FSimpleUGCCreator>
+{
+public:
+
+ FSimpleUGCCreator();
+ ~FSimpleUGCCreator();
+
+ /**
+ * Opens the mod creator wizard.
+ * @param bSuppressErrors If false, a dialog will be shown if the wizard cannot be opened for whatever reason
+ */
+ void OpenNewPluginWizard(bool bSuppressErrors = false) const;
+
+ /** The name to use when creating the tab for the tab spawner */
+ static const FName SimpleUGCEditorPluginCreatorName;
+
+private:
+ /** Registers a nomad tab spawner that will create the mod wizard */
+ void RegisterTabSpawner();
+
+ /** Unregisters the nomad tab spawner */
+ void UnregisterTabSpawner();
+
+ /** Spawns the tab that hosts the mod creator wizard widget */
+ TSharedRef<SDockTab> HandleSpawnPluginTab(const class FSpawnTabArgs& SpawnTabArgs);
+}; \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditor.h b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditor.h
new file mode 100644
index 0000000..574e7d9
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditor.h
@@ -0,0 +1,41 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Slate.h"
+#include "SimpleUGCPackager.h"
+#include "Modules\ModuleManager.h"
+
+class FToolBarBuilder;
+class FMenuBuilder;
+
+class FSimpleUGCEditorModule : public IModuleInterface
+{
+public:
+
+ /** IModuleInterface implementation */
+ virtual void StartupModule() override;
+ virtual void ShutdownModule() override;
+
+ // When the Create Button is clicked
+ void CreateUGCButtonClicked();
+
+ /** Adds the plugin creator as a new toolbar button */
+ void AddUGCCreatorToolbarExtension(FToolBarBuilder& Builder);
+
+ /** Adds the plugin creator as a new menu option */
+ void AddUGCCreatorMenuExtension(FMenuBuilder& Builder);
+
+ /** Adds the plugin packager as a new toolbar button */
+ void AddUGCPackagerToolbarExtension(FToolBarBuilder& Builder);
+
+ /** Adds the plugin packager as a new menu option */
+ void AddUGCPackagerMenuExtension(FMenuBuilder& Builder);
+
+private:
+
+ TSharedPtr<class FSimpleUGCCreator> UGCCreator;
+ TSharedPtr<class FSimpleUGCPackager> UGCPackager;
+ TSharedPtr<class FUICommandList> PluginCommands;
+}; \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorCommands.h b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorCommands.h
new file mode 100644
index 0000000..247340c
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorCommands.h
@@ -0,0 +1,27 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Framework/Commands/Commands.h"
+#include "SimpleUGCEditorStyle.h"
+
+class FSimpleUGCEditorCommands : public TCommands<FSimpleUGCEditorCommands>
+{
+public:
+
+ FSimpleUGCEditorCommands()
+ : TCommands<FSimpleUGCEditorCommands>(TEXT("SimpleUGCEditor"), NSLOCTEXT("Contexts", "SimpleUGCEditor", "SimpleUGCEditor Plugin"), NAME_None, FSimpleUGCEditorStyle::GetStyleSetName())
+ {
+ }
+
+ // TCommands<> interface
+ virtual void RegisterCommands() override;
+
+ TArray<TSharedPtr<FUICommandInfo>> RegisterUGCCommands(const TArray<TSharedRef<class IPlugin>>& UGCList) const;
+ void UnregisterUGCCommands(TArray<TSharedPtr<FUICommandInfo>>& UICommands) const;
+
+public:
+ TSharedPtr< FUICommandInfo > CreateUGCAction;
+ TSharedPtr< FUICommandInfo > PackageUGCAction;
+}; \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorStyle.h b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorStyle.h
new file mode 100644
index 0000000..46f4843
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCEditorStyle.h
@@ -0,0 +1,31 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Styling/SlateStyle.h"
+
+class FSimpleUGCEditorStyle
+{
+public:
+
+ static void Initialize();
+
+ static void Shutdown();
+
+ /** reloads textures used by slate renderer */
+ static void ReloadTextures();
+
+ /** @return The Slate style set for the Shooter game */
+ static const ISlateStyle& Get();
+
+ static FName GetStyleSetName();
+
+private:
+
+ static TSharedRef< class FSlateStyleSet > Create();
+
+private:
+
+ static TSharedPtr< class FSlateStyleSet > StyleInstance;
+}; \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPackager.h b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPackager.h
new file mode 100644
index 0000000..f287732
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPackager.h
@@ -0,0 +1,49 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+
+struct FSimpleUGCCommand
+{
+ TSharedPtr<class IPlugin> PluginInfo;
+ TSharedPtr<class FUICommandInfo> CommandInfo;
+};
+
+class FSimpleUGCPackager : public TSharedFromThis<FSimpleUGCPackager>
+{
+public:
+ FSimpleUGCPackager();
+ ~FSimpleUGCPackager();
+
+ void OpenPluginPackager(TSharedRef<class IPlugin> Plugin);
+
+ void PackagePlugin(TSharedRef<class IPlugin> Plugin, const FString& OutputDirectory);
+
+ /** Generates submenu content for the plugin packager command */
+ void GeneratePackagerMenuContent(class FMenuBuilder& MenuBuilder);
+
+ /** Generates the menu content for the plugin packager toolbar button */
+ TSharedRef<class SWidget> GeneratePackagerComboButtonContent();
+
+private:
+ /** Gets all available game mod plugin packages */
+ void FindAvailableGameMods(TArray<TSharedRef<class IPlugin>>& OutAvailableGameMods);
+
+ /** Gets all available game mod plugins and registers command info for them */
+ void GetAvailableUGCCommands(const TArray<TSharedRef<class IPlugin>>& AvailableUGC);
+
+ /** Generates menu content for the supplied set of commands */
+ void GeneratePackagerMenuContent_Internal(class FMenuBuilder& MenuBuilder, const TArray<TSharedPtr<FUICommandInfo>>& Commands);
+
+ /**
+ * Checks if a plugin has any unsaved content
+ *
+ * @param Plugin The plugin to check for unsaved content
+ * @return True if all mod content has been saved, false otherwise
+ */
+ bool IsAllContentSaved(TSharedRef<class IPlugin> Plugin);
+
+private:
+ TArray<TSharedPtr<class FUICommandInfo>> UGCCommands;
+};
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPluginWizardDefinition.h b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPluginWizardDefinition.h
new file mode 100644
index 0000000..9543a27
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/Public/SimpleUGCPluginWizardDefinition.h
@@ -0,0 +1,70 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+// Depends on code from the plugin browser to work correctly
+#include "../../../../Plugins/Editor/PluginBrowser/Source/PluginBrowser/Public/IPluginWizardDefinition.h"
+
+class FSimpleUGCPluginWizardDefinition : public IPluginWizardDefinition
+{
+public:
+ FSimpleUGCPluginWizardDefinition();
+
+ // Begin IPluginWizardDefinition interface
+ virtual const TArray<TSharedRef<FPluginTemplateDescription>>& GetTemplatesSource() const override;
+ virtual void OnTemplateSelectionChanged(TArray<TSharedRef<FPluginTemplateDescription>> InSelectedItems, ESelectInfo::Type SelectInfo) override;
+ virtual TArray<TSharedPtr<FPluginTemplateDescription>> GetSelectedTemplates() const override;
+ virtual void ClearTemplateSelection() override;
+ virtual bool HasValidTemplateSelection() const override;
+
+ virtual ESelectionMode::Type GetSelectionMode() const override { return ESelectionMode::Multi; }
+ virtual bool AllowsEnginePlugins() const override { return false; }
+ virtual bool CanShowOnStartup() const override { return true; }
+ virtual bool CanContainContent() const override;
+ virtual bool HasModules() const override;
+ virtual bool IsMod() const override;
+ virtual void OnShowOnStartupCheckboxChanged(ECheckBoxState CheckBoxState) override;
+ virtual ECheckBoxState GetShowOnStartupCheckBoxState() const override;
+ virtual TSharedPtr<class SWidget> GetCustomHeaderWidget() override;
+ virtual FText GetInstructions() const override;
+
+ virtual bool GetPluginIconPath(FString& OutIconPath) const override;
+ virtual EHostType::Type GetPluginModuleDescriptor() const override;
+ virtual ELoadingPhase::Type GetPluginLoadingPhase() const override;
+ virtual bool GetTemplateIconPath(TSharedRef<FPluginTemplateDescription> InTemplate, FString& OutIconPath) const override;
+ virtual FString GetPluginFolderPath() const override;
+ virtual TArray<FString> GetFoldersForSelection() const override;
+ virtual void PluginCreated(const FString& PluginName, bool bWasSuccessful) const override;
+ // End IPluginWizardDefinition interface
+
+private:
+ /** The available templates for the mod. They should function as mixins to the backing template */
+ TArray<TSharedRef<FPluginTemplateDescription>> TemplateDefinitions;
+
+ /** The content that will be used when creating the mod */
+ TArray<TSharedRef<FPluginTemplateDescription>> SelectedTemplates;
+
+ /** The base directory of this plugin. Used for accessing the templates used to create mods */
+ FString PluginBaseDir;
+
+ /**
+ * The path to the template that ultimately serves as the template that the mod will be based on. It's not intended to be
+ * selected directly, but rather other templates will act as mixins to define what content will exist in the plugin.
+ */
+ FString BackingTemplatePath;
+
+ /** The backing template definition for the mod. This should never be directly selectable */
+ TSharedPtr<FPluginTemplateDescription> BackingTemplate;
+
+ /** The base code template definition. Can be directly selectable to create an "empty" code mod, but should be included with any code mod selection */
+ TSharedPtr<FPluginTemplateDescription> BaseCodeTemplate;
+
+ /** Maps a specific template to a specific icon file */
+ TMap<FString, FString> TemplateToIconMap;
+
+ /** Brush used for drawing the custom header widget */
+ TSharedPtr<struct FSlateDynamicImageBrush> IconBrush;
+
+ /** Custom header widget */
+ TSharedPtr<class SWidget> CustomHeaderWidget;
+}; \ No newline at end of file
diff --git a/Plugins/SimpleUGC/Source/SimpleUGCEditor/SimpleUGCEditor.Build.cs b/Plugins/SimpleUGC/Source/SimpleUGCEditor/SimpleUGCEditor.Build.cs
new file mode 100644
index 0000000..b2168f5
--- /dev/null
+++ b/Plugins/SimpleUGC/Source/SimpleUGCEditor/SimpleUGCEditor.Build.cs
@@ -0,0 +1,59 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+using UnrealBuildTool;
+
+public class SimpleUGCEditor : ModuleRules
+{
+ public SimpleUGCEditor(ReadOnlyTargetRules Target) : base(Target)
+ {
+ PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
+
+ PublicIncludePaths.AddRange(
+ new string[] {
+ // ... add public include paths required here ...
+ }
+ );
+
+
+ PrivateIncludePaths.AddRange(
+ new string[] {
+ // ... add other private include paths required here ...
+ }
+ );
+
+
+ PublicDependencyModuleNames.AddRange(
+ new string[]
+ {
+ "Core",
+ "PluginBrowser",
+ // ... add other public dependencies that you statically link with here ...
+ }
+ );
+
+
+ PrivateDependencyModuleNames.AddRange(
+ new string[]
+ {
+ "Projects",
+ "InputCore",
+ "UnrealEd",
+ "LevelEditor",
+ "CoreUObject",
+ "Engine",
+ "PluginBrowser",
+ "Slate",
+ "SlateCore",
+ // ... add private dependencies that you statically link with here ...
+ }
+ );
+
+
+ DynamicallyLoadedModuleNames.AddRange(
+ new string[]
+ {
+ // ... add any modules that your module loads dynamically here ...
+ }
+ );
+ }
+}
diff --git a/Plugins/SimpleUGC/Templates/BaseTemplate/Resources/Icon128.png b/Plugins/SimpleUGC/Templates/BaseTemplate/Resources/Icon128.png
new file mode 100644
index 0000000..85b65e7
--- /dev/null
+++ b/Plugins/SimpleUGC/Templates/BaseTemplate/Resources/Icon128.png
Binary files differ