Co-authored-by: Mateus Rodrigues <mateuus27@outlook.com> Co-committed-by: Mateus Rodrigues <mateuus27@outlook.com>
224 lines
5.3 KiB
C++
224 lines
5.3 KiB
C++
#include "ZMMOThemeSubsystem.h"
|
|
|
|
#include "ZMMOThemeDataAsset.h"
|
|
#include "Engine/DataTable.h"
|
|
#include "Engine/Texture2D.h"
|
|
#include "Sound/SoundBase.h"
|
|
#include "NiagaraSystem.h"
|
|
#include "Misc/DateTime.h"
|
|
#include "UI/ThemeCalendarRow.h"
|
|
#include "UI/UIStyleRow.h"
|
|
|
|
namespace
|
|
{
|
|
/** Row Name da linha de estilo de fallback em DT_UI_Styles. */
|
|
const FName GUIStyleDefaultRow(TEXT("Default"));
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|
{
|
|
Super::Initialize(Collection);
|
|
|
|
DefaultTheme = DefaultThemeAsset.LoadSynchronous();
|
|
if (!DefaultTheme)
|
|
{
|
|
UE_LOG(LogTemp, Warning,
|
|
TEXT("[ZMMOThemeSubsystem] DefaultThemeAsset is not set. UI will have no theme."));
|
|
}
|
|
|
|
ResolveActiveTheme();
|
|
|
|
// Garantia: se ResolveActiveTheme não disparou ResolveActiveUIStyle (porque
|
|
// ActiveTheme não mudou — caso comum quando DefaultTheme é nullptr e nada
|
|
// resolveu), força a carga do DT_UI_Styles agora para não deixar
|
|
// ActiveUIStyle como FUIStyle() default (brushes vazios → nada renderiza
|
|
// em runtime). O fallback interno acha a linha "Default" do DT.
|
|
ResolveActiveUIStyle(ActiveThemeId);
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::Deinitialize()
|
|
{
|
|
ActiveTheme = nullptr;
|
|
DefaultTheme = nullptr;
|
|
Super::Deinitialize();
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::ApplyServerTheme(FName ThemeId)
|
|
{
|
|
ServerThemeId = ThemeId;
|
|
ResolveActiveTheme();
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::ForceTheme(FName ThemeId)
|
|
{
|
|
ForcedThemeId = ThemeId;
|
|
ResolveActiveTheme();
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::ClearForcedTheme()
|
|
{
|
|
ForcedThemeId = NAME_None;
|
|
ResolveActiveTheme();
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::ResolveActiveTheme()
|
|
{
|
|
FName Resolved = NAME_None;
|
|
|
|
if (!ForcedThemeId.IsNone())
|
|
{
|
|
Resolved = ForcedThemeId;
|
|
}
|
|
#if !UE_BUILD_SHIPPING
|
|
else if (!DevThemeOverride.IsNone())
|
|
{
|
|
Resolved = DevThemeOverride;
|
|
}
|
|
#endif
|
|
else if (!ServerThemeId.IsNone())
|
|
{
|
|
Resolved = ServerThemeId;
|
|
}
|
|
else
|
|
{
|
|
Resolved = ResolveByCalendar();
|
|
}
|
|
|
|
UZMMOThemeDataAsset* NewActive = !Resolved.IsNone() ? LoadThemeById(Resolved) : nullptr;
|
|
if (!NewActive)
|
|
{
|
|
NewActive = DefaultTheme;
|
|
Resolved = DefaultTheme ? DefaultTheme->ThemeId : NAME_None;
|
|
}
|
|
|
|
if (NewActive != ActiveTheme || Resolved != ActiveThemeId)
|
|
{
|
|
ActiveTheme = NewActive;
|
|
ActiveThemeId = Resolved;
|
|
ResolveActiveUIStyle(ActiveThemeId);
|
|
OnThemeChanged.Broadcast(ActiveThemeId);
|
|
}
|
|
}
|
|
|
|
void UZMMOThemeSubsystem::ResolveActiveUIStyle(FName ThemeId)
|
|
{
|
|
// Reset para os defaults do struct antes de aplicar a linha resolvida —
|
|
// assim um tema sem linha cai num estado coerente (paleta Aurora Arcana).
|
|
ActiveUIStyle = FUIStyle();
|
|
|
|
UDataTable* Table = UIStyleTable.LoadSynchronous();
|
|
if (!Table)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FUIStyleRow* Row = nullptr;
|
|
if (!ThemeId.IsNone())
|
|
{
|
|
Row = Table->FindRow<FUIStyleRow>(ThemeId, TEXT("UIStyle"));
|
|
}
|
|
if (!Row)
|
|
{
|
|
// Fallback: linha "Default" (mesma política dos assets, §5).
|
|
Row = Table->FindRow<FUIStyleRow>(GUIStyleDefaultRow, TEXT("UIStyle"));
|
|
}
|
|
if (Row)
|
|
{
|
|
ActiveUIStyle = Row->Style;
|
|
}
|
|
}
|
|
|
|
FName UZMMOThemeSubsystem::ResolveByCalendar() const
|
|
{
|
|
UDataTable* Table = CalendarTable.LoadSynchronous();
|
|
if (!Table)
|
|
{
|
|
return NAME_None;
|
|
}
|
|
|
|
const FDateTime Now = FDateTime::Now();
|
|
const int32 NowMonth = Now.GetMonth();
|
|
const int32 NowDay = Now.GetDay();
|
|
const int32 NowMD = NowMonth * 100 + NowDay;
|
|
|
|
FName Best = NAME_None;
|
|
int32 BestPriority = MIN_int32;
|
|
|
|
TArray<FName> RowNames = Table->GetRowNames();
|
|
for (const FName& RowName : RowNames)
|
|
{
|
|
const FThemeCalendarRow* Row = Table->FindRow<FThemeCalendarRow>(RowName, TEXT("ThemeCalendar"));
|
|
if (!Row || Row->ThemeId.IsNone())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const int32 StartMD = Row->StartMonth * 100 + Row->StartDay;
|
|
const int32 EndMD = Row->EndMonth * 100 + Row->EndDay;
|
|
|
|
const bool bInRange = (StartMD <= EndMD)
|
|
? (NowMD >= StartMD && NowMD <= EndMD)
|
|
: (NowMD >= StartMD || NowMD <= EndMD); // wraps across year (e.g. 12-15 -> 01-05)
|
|
|
|
if (bInRange && Row->Priority > BestPriority)
|
|
{
|
|
Best = Row->ThemeId;
|
|
BestPriority = Row->Priority;
|
|
}
|
|
}
|
|
|
|
return Best;
|
|
}
|
|
|
|
UZMMOThemeDataAsset* UZMMOThemeSubsystem::LoadThemeById(FName ThemeId) const
|
|
{
|
|
if (const TSoftObjectPtr<UZMMOThemeDataAsset>* Soft = ThemeRegistry.Find(ThemeId))
|
|
{
|
|
return Soft->LoadSynchronous();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const FThemeEntry* UZMMOThemeSubsystem::FindEntryWithFallback(EZMMOThemeKey Key) const
|
|
{
|
|
if (ActiveTheme)
|
|
{
|
|
if (const FThemeEntry* Entry = ActiveTheme->FindEntry(Key))
|
|
{
|
|
return Entry;
|
|
}
|
|
}
|
|
if (DefaultTheme && DefaultTheme != ActiveTheme)
|
|
{
|
|
if (const FThemeEntry* Entry = DefaultTheme->FindEntry(Key))
|
|
{
|
|
return Entry;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
UTexture2D* UZMMOThemeSubsystem::GetTexture(EZMMOThemeKey Key) const
|
|
{
|
|
const FThemeEntry* Entry = FindEntryWithFallback(Key);
|
|
return Entry ? Entry->Texture.LoadSynchronous() : nullptr;
|
|
}
|
|
|
|
USoundBase* UZMMOThemeSubsystem::GetSound(EZMMOThemeKey Key) const
|
|
{
|
|
const FThemeEntry* Entry = FindEntryWithFallback(Key);
|
|
return Entry ? Entry->Sound.LoadSynchronous() : nullptr;
|
|
}
|
|
|
|
UNiagaraSystem* UZMMOThemeSubsystem::GetVFX(EZMMOThemeKey Key) const
|
|
{
|
|
const FThemeEntry* Entry = FindEntryWithFallback(Key);
|
|
return Entry ? Entry->VFX.LoadSynchronous() : nullptr;
|
|
}
|
|
|
|
UObject* UZMMOThemeSubsystem::GetGeneric(EZMMOThemeKey Key) const
|
|
{
|
|
const FThemeEntry* Entry = FindEntryWithFallback(Key);
|
|
return Entry ? Entry->Generic.LoadSynchronous() : nullptr;
|
|
}
|