246 lines
12 KiB
C++
246 lines
12 KiB
C++
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <optional>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include <Unreal/NameTypes.hpp>
|
||
|
|
|
||
|
|
#include "UnrealWrapper.hpp"
|
||
|
|
#include "UmgTypes.hpp"
|
||
|
|
#include "Widget.hpp"
|
||
|
|
#include "UserWidget.hpp"
|
||
|
|
#include "WidgetTree.hpp"
|
||
|
|
#include "CanvasPanel.hpp"
|
||
|
|
#include "Overlay.hpp"
|
||
|
|
#include "VerticalBox.hpp"
|
||
|
|
#include "TextBlock.hpp"
|
||
|
|
|
||
|
|
#include <Api/Pal/PalIndividual.hpp>
|
||
|
|
|
||
|
|
namespace PalUIExtension::Api
|
||
|
|
{
|
||
|
|
class MainMenuPalWidget : public UserWidget
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
static auto ClassPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C");
|
||
|
|
}
|
||
|
|
static auto DebugTag() -> const TCHAR* { return STR("MainMenuPal"); }
|
||
|
|
|
||
|
|
MainMenuPalWidget() = default;
|
||
|
|
explicit MainMenuPalWidget(UObject* Obj)
|
||
|
|
: UserWidget(Obj, ClassOf<MainMenuPalWidget>(), DebugTag()) {
|
||
|
|
}
|
||
|
|
|
||
|
|
auto CanvasPalName() const -> CanvasPanel { return WrapCanvas(STR("Canvas_PalName")); }
|
||
|
|
auto CanvasPalStatus() const -> CanvasPanel { return WrapCanvas(STR("Canvas_PalStatus")); }
|
||
|
|
auto CanvasSkillInfo() const -> CanvasPanel { return WrapCanvas(STR("Canvas_SkillInfo")); }
|
||
|
|
auto CanvasPartnerSkill() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanel_PartnerSkill")); }
|
||
|
|
auto CanvasPotencial() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanel_Potencial")); } // engine spelling
|
||
|
|
auto CanvasDebuff() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanelDebuff")); }
|
||
|
|
auto CanvasAwakening() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Awakening")); }
|
||
|
|
auto CanvasDropGuide() const -> CanvasPanel { return WrapCanvas(STR("Canvas_DropGuide")); }
|
||
|
|
|
||
|
|
auto CanvasLocked() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Locked")); }
|
||
|
|
auto CanvasUnlocked() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Unlocked")); }
|
||
|
|
auto CanvasLock1() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanelLock_1")); }
|
||
|
|
auto CanvasLockText() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanelLockText")); }
|
||
|
|
auto CanvasLockText1() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanelLockText_1")); }
|
||
|
|
|
||
|
|
auto BoxPalList() const -> VerticalBox { return WrapVBox(STR("VerticalBox_Pal_List")); }
|
||
|
|
auto BoxSkill() const -> VerticalBox { return WrapVBox(STR("VerticalBox_Skill")); }
|
||
|
|
|
||
|
|
auto OverlayCircle() const -> Overlay { return WrapOverlay(STR("Overlay_Circle")); }
|
||
|
|
auto OverlayIconCircle() const -> Overlay { return WrapOverlay(STR("Overlay_Icon_Circle")); }
|
||
|
|
auto OverlayIconSquare() const -> Overlay { return WrapOverlay(STR("Overlay_Icon_sq")); }
|
||
|
|
auto OverlaySquare() const -> Overlay { return WrapOverlay(STR("Overlay_sq")); }
|
||
|
|
|
||
|
|
auto GridSuitability() const -> UObject* { return BoundObject(STR("UniformGrid_Suitability")); }
|
||
|
|
|
||
|
|
auto FindCanvas(const TCHAR* Name) -> CanvasPanel { return Child<CanvasPanel>(Name); }
|
||
|
|
|
||
|
|
auto CachedHandle() const -> UObject* { return BoundObject(STR("CachedIndividualHandle")); }
|
||
|
|
|
||
|
|
auto CachedSpecies() const -> std::optional<FName>
|
||
|
|
{
|
||
|
|
return Pal::PalIndividual::CharacterIdFromHandle(CachedHandle());
|
||
|
|
}
|
||
|
|
auto CachedIdentity() const -> Pal::PalIdentity
|
||
|
|
{
|
||
|
|
return Pal::PalIndividual::Identify(CachedHandle());
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- screen state --------------------------------------------
|
||
|
|
|
||
|
|
auto IsShowingStatusWithList() const -> std::optional<bool> { return PropertyBoolValue(STR("isShowStatusWithList")); }
|
||
|
|
auto IsLocked() const -> std::optional<bool> { return PropertyBoolValue(STR("Is Lock")); }
|
||
|
|
auto IsEditingNickName() const -> std::optional<bool> { return PropertyBoolValue(STR("IsEditingNickName")); }
|
||
|
|
|
||
|
|
// ==============================================================
|
||
|
|
// WIDGET ARRAYS
|
||
|
|
// ==============================================================
|
||
|
|
|
||
|
|
auto PalPanels() const -> std::vector<UObject*> { return ReadObjectArray(STR("PalPanels")); }
|
||
|
|
auto ActiveSkillPanels() const -> std::vector<UObject*> { return ReadObjectArray(STR("ActiveSkillPanelArray")); }
|
||
|
|
auto PassiveSkillPanels() const -> std::vector<UObject*> { return ReadObjectArray(STR("PassiveSkillPanelArray")); }
|
||
|
|
auto ConditionWidgets() const -> std::vector<UObject*> { return ReadObjectArray(STR("ConditionWidgetArray")); }
|
||
|
|
auto RarityWidgets() const -> std::vector<UObject*> { return ReadObjectArray(STR("RarityWidgetArray")); }
|
||
|
|
|
||
|
|
// The engine's spelling of "SideInfo" is "SindeInfo". Lol.
|
||
|
|
auto SideInfoConditionWidgets() const -> std::vector<UObject*> { return ReadObjectArray(STR("SindeInfoConditionWidgetArray")); }
|
||
|
|
|
||
|
|
// ==============================================================
|
||
|
|
// TEXT
|
||
|
|
// ==============================================================
|
||
|
|
auto TextNowHP() const -> TextBlock { return WrapText(STR("Text_NowHP")); }
|
||
|
|
auto TextMaxHP() const -> TextBlock { return WrapText(STR("Text_MaxHP")); }
|
||
|
|
auto TextNowHunger() const -> TextBlock { return WrapText(STR("Text_NowHunger")); }
|
||
|
|
auto TextMaxHunger() const -> TextBlock { return WrapText(STR("Text_MaxHunger")); }
|
||
|
|
auto TextNowSanity() const -> TextBlock { return WrapText(STR("Text_NowSanity")); }
|
||
|
|
auto TextLevel() const -> TextBlock { return WrapText(STR("Text_LevelValue")); }
|
||
|
|
auto TextNextExp() const -> TextBlock { return WrapText(STR("Text_NextExp")); }
|
||
|
|
auto TextDefense() const -> TextBlock { return WrapText(STR("Text_DefenseValue")); }
|
||
|
|
auto TextRangeAttack() const -> TextBlock { return WrapText(STR("Text_RangeAttackValue")); }
|
||
|
|
auto TextWorkSpeed() const -> TextBlock { return WrapText(STR("Text_WorkSpeedValue")); }
|
||
|
|
auto TextFriendship() const -> TextBlock { return WrapText(STR("Text_FriendshipRank_Num")); }
|
||
|
|
auto TextNickName() const -> TextBlock { return WrapText(STR("BP_PalTextBlock_NickName")); }
|
||
|
|
auto TextLvLabel() const -> TextBlock { return WrapText(STR("BP_PalTextBlock_LvText")); }
|
||
|
|
auto TextSoulRank() const -> TextBlock { return WrapText(STR("BP_PalTextBlock_SoulRank")); }
|
||
|
|
|
||
|
|
auto RichTextPartnerSkillName() const -> UObject* { return BoundObject(STR("RichText_PartnerSkillName")); }
|
||
|
|
auto RichTextPartnerSkillDesc() const -> UObject* { return BoundObject(STR("RichText_PartnerSkillDesc")); }
|
||
|
|
|
||
|
|
// ---- gauges, images, nested widgets: raw ---------------------
|
||
|
|
|
||
|
|
auto GaugeHP() const -> UObject* { return BoundObject(STR("Gauge_HP")); }
|
||
|
|
auto GaugeHunger() const -> UObject* { return BoundObject(STR("Gauge_Hunger")); }
|
||
|
|
auto GaugeExp() const -> UObject* { return BoundObject(STR("Gauge_Exp")); }
|
||
|
|
auto GaugeFriendship() const -> UObject* { return BoundObject(STR("Gauge_Friendship")); }
|
||
|
|
|
||
|
|
auto ImageRare() const -> UObject* { return BoundObject(STR("Image_Rare")); }
|
||
|
|
auto ImageStrong() const -> UObject* { return BoundObject(STR("Image_Strong")); }
|
||
|
|
auto ImageMutant() const -> UObject* { return BoundObject(STR("Image_Mutant")); }
|
||
|
|
auto ImageLocked() const -> UObject* { return BoundObject(STR("Image_Icon_Locked")); }
|
||
|
|
auto ImageGlobalImport() const -> UObject* { return BoundObject(STR("Image_Icon_GlobalInport")); } // engine spelling
|
||
|
|
|
||
|
|
auto FoodAmountWidget() const -> UObject* { return BoundObject(STR("WBP_MainMenu_Pal_FoodAmount")); }
|
||
|
|
auto GenderIcon() const -> UObject* { return BoundObject(STR("WBP_PalGenderIcon")); }
|
||
|
|
auto SkillInfoWidget() const -> UObject* { return BoundObject(STR("WBP_MainMenu_PalSkillInfo")); }
|
||
|
|
auto PotencialWidget() const -> UObject* { return BoundObject(STR("WBP_Menu_Pal_Potencial")); } // engine spelling
|
||
|
|
auto NoDataWidget() const -> UObject* { return BoundObject(STR("WBP_NoData")); }
|
||
|
|
auto BuffTimers() const -> UObject* { return BoundObject(STR("WBP_StatusBuffTimerContainer")); }
|
||
|
|
auto KeyGuideIcon() const -> UObject* { return BoundObject(STR("WBP_PalKeyGuideIcon")); }
|
||
|
|
|
||
|
|
// ==============================================================
|
||
|
|
// HOOK TARGETS
|
||
|
|
// ==============================================================
|
||
|
|
|
||
|
|
static auto BindFromHandlePath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:BindFromHandle");
|
||
|
|
}
|
||
|
|
static auto SetPalHandlesPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:Set Pal Handles");
|
||
|
|
}
|
||
|
|
static auto SetupStatusPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:Setup Status");
|
||
|
|
}
|
||
|
|
static auto ListToStatusPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:ListToStatus");
|
||
|
|
}
|
||
|
|
static auto OnClickedPalButtonPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:OnClickedPalButtonEvent");
|
||
|
|
}
|
||
|
|
static auto OnHoveredPalButtonPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:OnHoveredPalButtonEvent");
|
||
|
|
}
|
||
|
|
// The honest bookends for "this screen exists" and "your cached
|
||
|
|
// pointers are now garbage." If you cache anything off this
|
||
|
|
// class, hook Destruct.
|
||
|
|
static auto ConstructPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:Construct");
|
||
|
|
}
|
||
|
|
static auto DestructPath() -> const TCHAR*
|
||
|
|
{
|
||
|
|
return STR("/Game/Pal/Blueprint/UI/UserInterface/MainMenu/Pal/"
|
||
|
|
"WBP_MainMenu_Pal_00.WBP_MainMenu_Pal_00_C:Destruct");
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- frames --------------------------------------------------
|
||
|
|
struct BindFromHandleFrame { UObject* targetHandle; };
|
||
|
|
struct HandleFrame { UObject* Handle; };
|
||
|
|
struct SetPalHandlesFrame
|
||
|
|
{
|
||
|
|
UObject** Data;
|
||
|
|
int32 Num;
|
||
|
|
int32 Max;
|
||
|
|
};
|
||
|
|
|
||
|
|
private:
|
||
|
|
auto WrapCanvas(const TCHAR* Name) const -> CanvasPanel
|
||
|
|
{
|
||
|
|
UObject* O = BoundObject(Name);
|
||
|
|
return O ? CanvasPanel{ O } : CanvasPanel{};
|
||
|
|
}
|
||
|
|
auto WrapVBox(const TCHAR* Name) const -> VerticalBox
|
||
|
|
{
|
||
|
|
UObject* O = BoundObject(Name);
|
||
|
|
return O ? VerticalBox{ O } : VerticalBox{};
|
||
|
|
}
|
||
|
|
auto WrapOverlay(const TCHAR* Name) const -> Overlay
|
||
|
|
{
|
||
|
|
UObject* O = BoundObject(Name);
|
||
|
|
return O ? Overlay{ O } : Overlay{};
|
||
|
|
}
|
||
|
|
auto WrapText(const TCHAR* Name) const -> TextBlock
|
||
|
|
{
|
||
|
|
UObject* O = BoundObject(Name);
|
||
|
|
return O ? TextBlock{ O } : TextBlock{};
|
||
|
|
}
|
||
|
|
|
||
|
|
static constexpr int32 kMaxPlausibleEntries = 1024;
|
||
|
|
|
||
|
|
auto ReadObjectArray(const TCHAR* PropertyName) const -> std::vector<UObject*>
|
||
|
|
{
|
||
|
|
std::vector<UObject*> Out;
|
||
|
|
|
||
|
|
auto* Arr = TryPropertyPtr<TArrayRead_<UObject*>>(PropertyName);
|
||
|
|
if (!Arr) return Out;
|
||
|
|
|
||
|
|
if (!Arr->IsPlausible(kMaxPlausibleEntries))
|
||
|
|
{
|
||
|
|
Output::send<LogLevel::Warning>(
|
||
|
|
STR("[{}] '{}' does not look like a live TArray (Num={}, Max={})\n"),
|
||
|
|
m_tag, PropertyName, Arr->Num, Arr->Max);
|
||
|
|
return Out;
|
||
|
|
}
|
||
|
|
|
||
|
|
Out.reserve(static_cast<size_t>(Arr->Num));
|
||
|
|
for (int32 i = 0; i < Arr->Num; ++i)
|
||
|
|
{
|
||
|
|
if (UObject* Entry = Arr->Data[i]) Out.push_back(Entry);
|
||
|
|
}
|
||
|
|
return Out;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
MainMenuPalWidget(UObject* Obj, UClass* Expected, const TCHAR* Tag)
|
||
|
|
: UserWidget(Obj, Expected, Tag) {
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|