From f2acd7eb4c63b38e588b71af10b709f262e4eebd Mon Sep 17 00:00:00 2001 From: "adnan.mujkic" Date: Mon, 5 Oct 2026 10:59:45 +0200 Subject: [PATCH] Editor toling to easier create data assets --- .../Private/Eleri/EleriAssetCategory.cpp | 45 ++++ .../Private/Eleri/EleriAssetCategory.h | 26 ++ .../Eleri/EleriDataAssetDefinitions.cpp | 253 ++++++++++++++++++ .../Private/Eleri/EleriDataAssetDefinitions.h | 235 ++++++++++++++++ .../Private/Eleri/EleriDataAssetFactories.cpp | 231 ++++++++++++++++ .../Private/Eleri/EleriDataAssetFactories.h | 238 ++++++++++++++++ .../Private/ProjectEleriEditorModule.cpp | 9 + .../ProjectEleriEditor.Build.cs | 6 + 8 files changed, 1043 insertions(+) create mode 100644 Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.cpp create mode 100644 Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.h create mode 100644 Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.cpp create mode 100644 Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.h create mode 100644 Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.cpp create mode 100644 Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.h diff --git a/Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.cpp b/Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.cpp new file mode 100644 index 00000000..571941c9 --- /dev/null +++ b/Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.cpp @@ -0,0 +1,45 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "EleriAssetCategory.h" + +#include "AssetToolsModule.h" +#include "IAssetTools.h" +#include "Internationalization/Text.h" +#include "Modules/ModuleManager.h" + +#define LOCTEXT_NAMESPACE "EleriAssetCategory" + +namespace EleriAssetCategory +{ + const FAssetCategoryPath& Get() + { + // A function-local static rather than a namespace-scope global: LOCTEXT has to run once the + // localization system is up, which this module's static initialisers cannot count on. + static const FAssetCategoryPath Category(LOCTEXT("Category", "Eleri")); + return Category; + } + + uint32 GetLegacyCategoryBit() + { + // The new Content Browser places a factory by the category path of the asset definition behind the + // class it supports. The older one still files the Add menu by an EAssetTypeCategories bitmask, and + // a bit for a category of our own only exists once someone has registered it. Doing that here, once + // and lazily, is what keeps the two paths pointing at the same entry instead of at two nearly + // identical ones. + static const uint32 Bit = []() + { + IAssetTools& AssetTools = FModuleManager::LoadModuleChecked(TEXT("AssetTools")).Get(); + + // The key the engine groups by is the source string of the path's first entry rather than the + // localized one, so an editor running in another language still lands in the same category. + const FAssetCategoryPath& Category = Get(); + return (uint32)AssetTools.RegisterAdvancedAssetCategory( + FName(*FTextInspector::GetSourceString(Category.GetCategoryText())), + Category.GetCategoryText()); + }(); + + return Bit; + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.h b/Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.h new file mode 100644 index 00000000..af2955c7 --- /dev/null +++ b/Source/ProjectEleriEditor/Private/Eleri/EleriAssetCategory.h @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Misc/AssetCategoryPath.h" + +/** + * The one category every data asset type of this project is filed under in the Content Browser. + * + * A category is a path rather than an enum entry: the asset definition a data asset type is described by + * hands this path to the engine, the engine derives the key it groups by from the path's source string, + * and both the Filters panel and the Add menu read that same list. Registering it with the Asset Tools + * as well is only what the older Content Browser style needs, which still files the Add menu by the + * EAssetTypeCategories bitmask instead of by the path. + */ +namespace EleriAssetCategory +{ + /** The shared category path. The reference is to a function-local static, so it is safe to copy from + * a definition's initialiser, but it must not be held on to once the module has been shut down. */ + const FAssetCategoryPath& Get(); + + /** The EAssetTypeCategories bit for this category, for UFactory::GetMenuCategories(). Registered on + * the first call and the same value on every call after it. */ + uint32 GetLegacyCategoryBit(); +} diff --git a/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.cpp b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.cpp new file mode 100644 index 00000000..f11bbd90 --- /dev/null +++ b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.cpp @@ -0,0 +1,253 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "EleriDataAssetDefinitions.h" + +#include "EleriAssetCategory.h" + +#include "ProjectEleri/Ai/NpcScheduleAsset.h" +#include "ProjectEleri/Animation/AnimationDataAsset.h" +#include "ProjectEleri/Data/BazarSettingsDataAsset.h" +#include "ProjectEleri/Data/FaceExpressionDataAsset.h" +#include "ProjectEleri/Data/Minigames/BaseMinigameDataAsset.h" +#include "ProjectEleri/Data/NpcDataAsset.h" +#include "ProjectEleri/Data/WeatherPresetDataAsset.h" +#include "ProjectEleri/DialogueSystem/QuestDatabase.h" +#include "ProjectEleri/DialogueSystem/SpeechDataAsset.h" +#include "ProjectEleri/GameEventSystem/GameEventDataAsset.h" +#include "ProjectEleri/Items/DataAssets/ItemDataAsset.h" +#include "ProjectEleri/Items/ItemContainer.h" +#include "ProjectEleri/QuestSystem/QuestDataAsset.h" + +#define LOCTEXT_NAMESPACE "EleriDataAssetDefinitions" + +/*----------------------------------------------------------------------------- + Shared behaviour +-----------------------------------------------------------------------------*/ + +TConstArrayView UEleriDataAssetDefinition::GetAssetCategories() const +{ + // One entry, the same for every definition in here. It has to outlive the call, because the engine + // keeps the view it is handed rather than copying it. + static const TArray Categories = { EleriAssetCategory::Get() }; + return Categories; +} + +/*----------------------------------------------------------------------------- + Items +-----------------------------------------------------------------------------*/ + +FText UEleriItemDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("ItemDataAssetName", "Item"); +} + +FLinearColor UEleriItemDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.86f, 0.33f, 0.10f); +} + +TSoftClassPtr UEleriItemDataAssetDefinition::GetAssetClass() const +{ + return UItemDataAsset::StaticClass(); +} + +FText UEleriItemContainerDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("ItemContainerName", "Item Container"); +} + +FLinearColor UEleriItemContainerDefinition::GetAssetColor() const +{ + return FLinearColor(0.85f, 0.55f, 0.10f); +} + +TSoftClassPtr UEleriItemContainerDefinition::GetAssetClass() const +{ + return UItemContainer::StaticClass(); +} + +/*----------------------------------------------------------------------------- + Quests and dialogue +-----------------------------------------------------------------------------*/ + +FText UEleriQuestDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("QuestDataAssetName", "Quest"); +} + +FLinearColor UEleriQuestDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.95f, 0.80f, 0.15f); +} + +TSoftClassPtr UEleriQuestDataAssetDefinition::GetAssetClass() const +{ + return UQuestDataAsset::StaticClass(); +} + +FText UEleriQuestDatabaseDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("QuestDatabaseName", "Quest Database"); +} + +FLinearColor UEleriQuestDatabaseDefinition::GetAssetColor() const +{ + return FLinearColor(0.65f, 0.62f, 0.15f); +} + +TSoftClassPtr UEleriQuestDatabaseDefinition::GetAssetClass() const +{ + return UQuestDatabase::StaticClass(); +} + +FText UEleriSpeechDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("SpeechDataAssetName", "Speech"); +} + +FLinearColor UEleriSpeechDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.35f, 0.70f, 0.85f); +} + +TSoftClassPtr UEleriSpeechDataAssetDefinition::GetAssetClass() const +{ + return USpeechDataAsset::StaticClass(); +} + +/*----------------------------------------------------------------------------- + World events and weather +-----------------------------------------------------------------------------*/ + +FText UEleriGameEventDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("GameEventDataAssetName", "Game Event"); +} + +FLinearColor UEleriGameEventDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.60f, 0.35f, 0.85f); +} + +TSoftClassPtr UEleriGameEventDataAssetDefinition::GetAssetClass() const +{ + return UGameEventDataAsset::StaticClass(); +} + +FText UEleriWeatherPresetDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("WeatherPresetDataAssetName", "Weather Preset"); +} + +FLinearColor UEleriWeatherPresetDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.30f, 0.60f, 0.90f); +} + +TSoftClassPtr UEleriWeatherPresetDataAssetDefinition::GetAssetClass() const +{ + return UWeatherPresetDataAsset::StaticClass(); +} + +/*----------------------------------------------------------------------------- + Characters +-----------------------------------------------------------------------------*/ + +FText UEleriFaceExpressionDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("FaceExpressionDataAssetName", "Face Expression"); +} + +FLinearColor UEleriFaceExpressionDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.95f, 0.55f, 0.70f); +} + +TSoftClassPtr UEleriFaceExpressionDataAssetDefinition::GetAssetClass() const +{ + return UFaceExpressionDataAsset::StaticClass(); +} + +FText UEleriNpcDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("NpcDataAssetName", "NPC"); +} + +FLinearColor UEleriNpcDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.30f, 0.75f, 0.55f); +} + +TSoftClassPtr UEleriNpcDataAssetDefinition::GetAssetClass() const +{ + return UNpcDataAsset::StaticClass(); +} + +FText UEleriNpcScheduleAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("NpcScheduleAssetName", "NPC Schedule"); +} + +FLinearColor UEleriNpcScheduleAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.20f, 0.60f, 0.45f); +} + +TSoftClassPtr UEleriNpcScheduleAssetDefinition::GetAssetClass() const +{ + return UNpcScheduleAsset::StaticClass(); +} + +/*----------------------------------------------------------------------------- + Settings, animation and minigames +-----------------------------------------------------------------------------*/ + +FText UEleriBazarSettingsDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("BazarSettingsDataAssetName", "Bazar Settings"); +} + +FLinearColor UEleriBazarSettingsDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.80f, 0.45f, 0.25f); +} + +TSoftClassPtr UEleriBazarSettingsDataAssetDefinition::GetAssetClass() const +{ + return UBazarSettingsDataAsset::StaticClass(); +} + +FText UEleriAnimationDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("AnimationDataAssetName", "Animation"); +} + +FLinearColor UEleriAnimationDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.45f, 0.45f, 0.85f); +} + +TSoftClassPtr UEleriAnimationDataAssetDefinition::GetAssetClass() const +{ + return UAnimationDataAsset::StaticClass(); +} + +FText UEleriMinigameDataAssetDefinition::GetAssetDisplayName() const +{ + return LOCTEXT("MinigameDataAssetName", "Minigame"); +} + +FLinearColor UEleriMinigameDataAssetDefinition::GetAssetColor() const +{ + return FLinearColor(0.85f, 0.30f, 0.55f); +} + +TSoftClassPtr UEleriMinigameDataAssetDefinition::GetAssetClass() const +{ + // The base class, deliberately: the engine answers for a class with the definition registered for + // its nearest ancestor that has one, so this single entry covers Potion Sort and every minigame + // added after it without any of them having to be listed here. + return UBaseMinigameDataAsset::StaticClass(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.h b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.h new file mode 100644 index 00000000..3501ca3e --- /dev/null +++ b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetDefinitions.h @@ -0,0 +1,235 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "AssetDefinitionDefault.h" + +#include "EleriDataAssetDefinitions.generated.h" + +/** + * One asset definition per data asset type of the project, all of them filed under the Eleri category. + * + * A definition is what tells the editor what a data asset type is called, what colour it is drawn in and + * which category it belongs to. Both halves of the Content Browser read that: the Filters panel builds a + * filter per definition out of it, and the Add menu files the factory behind a type by the category of + * the definition registered for the class that factory makes. A type therefore only has to say that it + * is an Eleri asset in one place to turn up in both. + * + * The engine registers these itself as the module loads, one per class, so there is nothing to do at + * startup beyond declaring them. A definition also answers for the subclasses of its class, which is why + * the minigame entry below is declared on the base and covers every minigame there is. + */ +UCLASS(Abstract) +class UEleriDataAssetDefinition : public UAssetDefinitionDefault +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual TConstArrayView GetAssetCategories() const override; + // End UAssetDefinition +}; + +/*----------------------------------------------------------------------------- + Items +-----------------------------------------------------------------------------*/ + +/** An item: the thing a player can hold, gather, grow or craft. */ +UCLASS() +class UEleriItemDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** A container: a named set of items, used where an inventory has to start with something in it. */ +UCLASS() +class UEleriItemContainerDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/*----------------------------------------------------------------------------- + Quests and dialogue +-----------------------------------------------------------------------------*/ + +/** A quest: its steps, the conditions it can be taken under and what it hands back. */ +UCLASS() +class UEleriQuestDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** The quest database: the asset every quest is looked up through. */ +UCLASS() +class UEleriQuestDatabaseDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** Speech: the lines an NPC says, and how they are said. */ +UCLASS() +class UEleriSpeechDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/*----------------------------------------------------------------------------- + World events and weather +-----------------------------------------------------------------------------*/ + +/** A game event: something the world does on a day, a condition or a trigger. */ +UCLASS() +class UEleriGameEventDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** A weather preset: the sky, the fog and the particles one kind of weather is made of. */ +UCLASS() +class UEleriWeatherPresetDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/*----------------------------------------------------------------------------- + Characters +-----------------------------------------------------------------------------*/ + +/** A face expression set: the sprites each of an NPC's moods is drawn from. */ +UCLASS() +class UEleriFaceExpressionDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** An NPC: who they are, how they look and what they are called. */ +UCLASS() +class UEleriNpcDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** An NPC schedule: a day of a character, as a list of places and the times they are in them. */ +UCLASS() +class UEleriNpcScheduleAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/*----------------------------------------------------------------------------- + Settings, animation and minigames +-----------------------------------------------------------------------------*/ + +/** The bazar settings: what the market spawns, how often and how it pays. */ +UCLASS() +class UEleriBazarSettingsDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** An animation set: which flipbook an action of a character plays. */ +UCLASS() +class UEleriAnimationDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; + +/** A minigame: the rules and the content one minigame is set up with. Declared on the base class, so + * this one entry stands in for every minigame in the project, Potion Sort included. */ +UCLASS() +class UEleriMinigameDataAssetDefinition : public UEleriDataAssetDefinition +{ + GENERATED_BODY() + +public: + // UAssetDefinition + virtual FText GetAssetDisplayName() const override; + virtual FLinearColor GetAssetColor() const override; + virtual TSoftClassPtr GetAssetClass() const override; + // End UAssetDefinition +}; diff --git a/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.cpp b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.cpp new file mode 100644 index 00000000..36f6fb30 --- /dev/null +++ b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.cpp @@ -0,0 +1,231 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "EleriDataAssetFactories.h" + +#include "EleriAssetCategory.h" + +#include "Engine/DataAsset.h" + +#include "ProjectEleri/Ai/NpcScheduleAsset.h" +#include "ProjectEleri/Animation/AnimationDataAsset.h" +#include "ProjectEleri/Data/BazarSettingsDataAsset.h" +#include "ProjectEleri/Data/FaceExpressionDataAsset.h" +#include "ProjectEleri/Data/Minigames/PotionSortDataAsset.h" +#include "ProjectEleri/Data/NpcDataAsset.h" +#include "ProjectEleri/Data/WeatherPresetDataAsset.h" +#include "ProjectEleri/DialogueSystem/QuestDatabase.h" +#include "ProjectEleri/DialogueSystem/SpeechDataAsset.h" +#include "ProjectEleri/GameEventSystem/GameEventDataAsset.h" +#include "ProjectEleri/Items/DataAssets/ItemDataAsset.h" +#include "ProjectEleri/Items/ItemContainer.h" +#include "ProjectEleri/QuestSystem/QuestDataAsset.h" + +#define LOCTEXT_NAMESPACE "EleriDataAssetFactories" + +/*----------------------------------------------------------------------------- + Shared behaviour +-----------------------------------------------------------------------------*/ + +UEleriDataAssetFactory::UEleriDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // What these make is always a data asset, and the class is the only thing that separates one from + // the next, so that is all a subclass has to set. bCreateNew is what admits a factory to the Add + // menu, and bEditAfterNew is what opens the asset once it exists, which for a data asset means the + // details panel a fresh one has to be filled in through. + bCreateNew = true; + bEditAfterNew = true; + bEditorImport = false; +} + +bool UEleriDataAssetFactory::ConfigureProperties() +{ + // Nothing to ask about. Each factory makes the one class it is named after, so the class picker the + // engine would otherwise open here would be a dialog with a single entry in it. + return true; +} + +uint32 UEleriDataAssetFactory::GetMenuCategories() const +{ + return EleriAssetCategory::GetLegacyCategoryBit(); +} + +UObject* UEleriDataAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + // SupportedClass rather than InClass: the Content Browser runs whichever factory it was asked to, + // and going through this factory's own member keeps the two from ever disagreeing. + UClass* ClassToCreate = SupportedClass.Get(); + if (!ensureMsgf(ClassToCreate, TEXT("%s has no supported class, so there is nothing to create"), *GetName())) + { + return nullptr; + } + + return NewObject(InParent, ClassToCreate, InName, Flags | RF_Transactional); +} + +/*----------------------------------------------------------------------------- + Items +-----------------------------------------------------------------------------*/ + +UEleriItemDataAssetFactory::UEleriItemDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UItemDataAsset::StaticClass(); +} + +FText UEleriItemDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("ItemFactoryName", "Item"); +} + +UEleriItemContainerFactory::UEleriItemContainerFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UItemContainer::StaticClass(); +} + +FText UEleriItemContainerFactory::GetDisplayName() const +{ + return LOCTEXT("ItemContainerFactoryName", "Item Container"); +} + +/*----------------------------------------------------------------------------- + Quests and dialogue +-----------------------------------------------------------------------------*/ + +UEleriQuestDataAssetFactory::UEleriQuestDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UQuestDataAsset::StaticClass(); +} + +FText UEleriQuestDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("QuestFactoryName", "Quest"); +} + +UEleriQuestDatabaseFactory::UEleriQuestDatabaseFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UQuestDatabase::StaticClass(); +} + +FText UEleriQuestDatabaseFactory::GetDisplayName() const +{ + return LOCTEXT("QuestDatabaseFactoryName", "Quest Database"); +} + +UEleriSpeechDataAssetFactory::UEleriSpeechDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = USpeechDataAsset::StaticClass(); +} + +FText UEleriSpeechDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("SpeechFactoryName", "Speech"); +} + +/*----------------------------------------------------------------------------- + World events and weather +-----------------------------------------------------------------------------*/ + +UEleriGameEventDataAssetFactory::UEleriGameEventDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UGameEventDataAsset::StaticClass(); +} + +FText UEleriGameEventDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("GameEventFactoryName", "Game Event"); +} + +UEleriWeatherPresetDataAssetFactory::UEleriWeatherPresetDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UWeatherPresetDataAsset::StaticClass(); +} + +FText UEleriWeatherPresetDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("WeatherPresetFactoryName", "Weather Preset"); +} + +/*----------------------------------------------------------------------------- + Characters +-----------------------------------------------------------------------------*/ + +UEleriFaceExpressionDataAssetFactory::UEleriFaceExpressionDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UFaceExpressionDataAsset::StaticClass(); +} + +FText UEleriFaceExpressionDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("FaceExpressionFactoryName", "Face Expression"); +} + +UEleriNpcDataAssetFactory::UEleriNpcDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UNpcDataAsset::StaticClass(); +} + +FText UEleriNpcDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("NpcFactoryName", "NPC"); +} + +UEleriNpcScheduleAssetFactory::UEleriNpcScheduleAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UNpcScheduleAsset::StaticClass(); +} + +FText UEleriNpcScheduleAssetFactory::GetDisplayName() const +{ + return LOCTEXT("NpcScheduleFactoryName", "NPC Schedule"); +} + +/*----------------------------------------------------------------------------- + Settings, animation and minigames +-----------------------------------------------------------------------------*/ + +UEleriBazarSettingsDataAssetFactory::UEleriBazarSettingsDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UBazarSettingsDataAsset::StaticClass(); +} + +FText UEleriBazarSettingsDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("BazarSettingsFactoryName", "Bazar Settings"); +} + +UEleriAnimationDataAssetFactory::UEleriAnimationDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UAnimationDataAsset::StaticClass(); +} + +FText UEleriAnimationDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("AnimationFactoryName", "Animation"); +} + +UEleriPotionSortDataAssetFactory::UEleriPotionSortDataAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // The concrete minigame rather than the base class the definition sits on: the base exists to be + // inherited from, so offering to make a bare one would only ever produce an asset with nothing in it. + SupportedClass = UPotionSortDataAsset::StaticClass(); +} + +FText UEleriPotionSortDataAssetFactory::GetDisplayName() const +{ + return LOCTEXT("PotionSortFactoryName", "Potion Sort Minigame"); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.h b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.h new file mode 100644 index 00000000..75db3f8a --- /dev/null +++ b/Source/ProjectEleriEditor/Private/Eleri/EleriDataAssetFactories.h @@ -0,0 +1,238 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Factories/Factory.h" + +#include "EleriDataAssetFactories.generated.h" + +/** + * The factories behind the data asset types the Eleri category offers, one per type. + * + * A factory is what puts a type into the Content Browser's Add menu, and the engine files it there by + * asking the asset definition of the class it supports where that class belongs, so a factory only has + * to name the class it makes. It also hands back the EAssetTypeCategories bit for the Eleri category, + * which is what the older Content Browser style groups the Add menu by, so the group holds together + * whichever of the two styles is in use. + * + * These only ever create the class they are named after. There is nothing to configure, so the factory + * goes straight to creating the asset as soon as it is picked. + */ +UCLASS(Abstract) +class UEleriDataAssetFactory : public UFactory +{ + GENERATED_BODY() + +public: + UEleriDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual bool ConfigureProperties() override; + virtual uint32 GetMenuCategories() const override; + virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + // End UFactory +}; + +/*----------------------------------------------------------------------------- + Items +-----------------------------------------------------------------------------*/ + +/** Creates a new item data asset. */ +UCLASS() +class UEleriItemDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriItemDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new item container. */ +UCLASS() +class UEleriItemContainerFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriItemContainerFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/*----------------------------------------------------------------------------- + Quests and dialogue +-----------------------------------------------------------------------------*/ + +/** Creates a new quest. */ +UCLASS() +class UEleriQuestDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriQuestDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new quest database. */ +UCLASS() +class UEleriQuestDatabaseFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriQuestDatabaseFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new speech asset. */ +UCLASS() +class UEleriSpeechDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriSpeechDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/*----------------------------------------------------------------------------- + World events and weather +-----------------------------------------------------------------------------*/ + +/** Creates a new game event. */ +UCLASS() +class UEleriGameEventDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriGameEventDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new weather preset. */ +UCLASS() +class UEleriWeatherPresetDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriWeatherPresetDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/*----------------------------------------------------------------------------- + Characters +-----------------------------------------------------------------------------*/ + +/** Creates a new face expression set. */ +UCLASS() +class UEleriFaceExpressionDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriFaceExpressionDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new NPC. */ +UCLASS() +class UEleriNpcDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriNpcDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new NPC schedule. */ +UCLASS() +class UEleriNpcScheduleAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriNpcScheduleAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/*----------------------------------------------------------------------------- + Settings, animation and minigames +-----------------------------------------------------------------------------*/ + +/** Creates a new bazar settings asset. */ +UCLASS() +class UEleriBazarSettingsDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriBazarSettingsDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new animation set. */ +UCLASS() +class UEleriAnimationDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriAnimationDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; + +/** Creates a new Potion Sort minigame. The category entry it turns up under is declared on the + * minigame base class, so a minigame added later needs its own factory here but no category. */ +UCLASS() +class UEleriPotionSortDataAssetFactory : public UEleriDataAssetFactory +{ + GENERATED_BODY() + +public: + UEleriPotionSortDataAssetFactory(const FObjectInitializer& ObjectInitializer); + + // UFactory + virtual FText GetDisplayName() const override; + // End UFactory +}; diff --git a/Source/ProjectEleriEditor/Private/ProjectEleriEditorModule.cpp b/Source/ProjectEleriEditor/Private/ProjectEleriEditorModule.cpp index 413e1e6d..7882eaaa 100644 --- a/Source/ProjectEleriEditor/Private/ProjectEleriEditorModule.cpp +++ b/Source/ProjectEleriEditor/Private/ProjectEleriEditorModule.cpp @@ -13,6 +13,15 @@ #include "NpcScheduleAssetCustomization.h" #include "ScheduleAssetRecheck.h" +// The asset definitions and factories that file every data asset type of the project under the Eleri +// category in the Content Browser. Nothing below calls into any of them: a definition registers itself +// with the engine as its class is loaded, and the factories are only ever run by the Content Browser, so +// declaring these files here is the whole of the wiring. They are included so that this file states +// where the category comes from rather than leaving it to be found by reading the folder. +#include "Eleri/EleriAssetCategory.h" +#include "Eleri/EleriDataAssetDefinitions.h" +#include "Eleri/EleriDataAssetFactories.h" + #define LOCTEXT_NAMESPACE "ProjectEleriEditorModule" IMPLEMENT_GAME_MODULE(FProjectEleriEditorModule, ProjectEleriEditor); diff --git a/Source/ProjectEleriEditor/ProjectEleriEditor.Build.cs b/Source/ProjectEleriEditor/ProjectEleriEditor.Build.cs index 3bc1b10f..87d06b87 100644 --- a/Source/ProjectEleriEditor/ProjectEleriEditor.Build.cs +++ b/Source/ProjectEleriEditor/ProjectEleriEditor.Build.cs @@ -21,6 +21,12 @@ public class ProjectEleriEditor : ModuleRules "Projects", "ToolMenus", "AssetRegistry", + // Asset categories are what the Content Browser files assets by, and in the engine version this + // project builds against a data asset type declares its own category as an asset definition + // rather than as an asset type action. AssetTools is still needed for the category bit the + // older Content Browser style files the Add menu by. + "AssetDefinition", + "AssetTools", "ContentBrowser", // The world map builder drives a scene capture and reads the render target back on the CPU, which // is where the render thread and the pixel formats it copies between come in.