#pragma once #include #include #include #include #include "UmgTypes.hpp" #include "UnrealWrapper.hpp" #include "Widget.hpp" #include "UserWidget.hpp" #include "WidgetTree.hpp" #include "TextBlock.hpp" #include "CanvasPanel.hpp" #include #include #include using namespace PalUIExtension::Api::Pal; namespace PalUIExtension::Api { class PalDetailWidget : public UserWidget { public: static auto ClassPath() -> const TCHAR* { return STR("/Game/Pal/Blueprint/UI/UserInterface/IngameMenu/PalBox/WBP_IngameMenu_PalBox_PalDetail.WBP_IngameMenu_PalBox_PalDetail_C"); } static auto WidgetTreePath() -> const TCHAR* { return STR("/Game/Pal/Blueprint/UI/UserInterface/IngameMenu/PalBox/WBP_IngameMenu_PalBox_PalDetail.WBP_IngameMenu_PalBox_PalDetail_C:WidgetTree"); } static auto DebugTag() -> const TCHAR* { return STR("PalDetail"); } PalDetailWidget() = default; explicit PalDetailWidget(UObject* Obj) : UserWidget(Obj, ClassOf(), DebugTag()) { } struct GetBindedHandleFrame { UObject* targetHandle; // 0x00 out bool bValidSoftRef; // 0x08 uint8 Pad09[7]; // 0x09 UObject* SoftRefAsObject; // 0x10 UObject* CastAsHandle; // 0x18 bool bCastSucceeded; // 0x20 uint8 Pad21[7]; // 0x21 }; static_assert(sizeof(GetBindedHandleFrame) == 40, "GetBindedHandle frame is 40 bytes on the dumped build"); struct GetBindedIndividualParameterFrame { UObject* IndividualParameter; // 0x00 out UObject* Handle; // 0x08 UObject* TryGetResult; // 0x10 bool bValid0; // 0x18 bool bValid1; // 0x19 uint8 Pad1A[6]; // 0x1A }; static_assert(sizeof(GetBindedIndividualParameterFrame) == 32, "GetBindedIndividualParameter frame is 32 bytes on the dumped build"); auto GetBindedHandle() -> UObject* { GetBindedHandleFrame p{}; if (!Call(STR("GetBindedHandle"), p)) return nullptr; return p.targetHandle; } auto GetBindedIndividualParameter() -> UObject* { GetBindedIndividualParameterFrame p{}; if (!Call(STR("GetBindedIndividualParameter"), p)) return nullptr; return p.IndividualParameter; } auto CurrentHandle() -> PalIndividualCharacterHandle { UObject* H = GetBindedHandle(); return H ? PalIndividualCharacterHandle{ H } : PalIndividualCharacterHandle{}; } auto CurrentParameter() -> PalIndividualCharacterParameter { UObject* P = GetBindedIndividualParameter(); return P ? PalIndividualCharacterParameter{ P } : PalIndividualCharacterParameter{}; } auto ResolveIdentity() -> PalIdentity { if (UObject* Param = GetBindedIndividualParameter()) { return PalIndividual::IdentifyFromParameter(Param); } return PalIndividual::Identify(GetBindedHandle()); } auto CurrentCharacterId() -> std::optional { if (UObject* Param = GetBindedIndividualParameter()) { return PalIndividual::CharacterId(Param); } return PalIndividual::CharacterIdFromHandle(GetBindedHandle()); } auto CanvasBase() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Base")); } auto CanvasBaseToolTip() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Base_ToolTip")); } auto CanvasInfo() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Info")); } auto CanvasFood() const -> CanvasPanel { return WrapCanvas(STR("Canvas_Food")); } auto CanvasPartnerSkill() const -> CanvasPanel { return WrapCanvas(STR("Canvas_PartnerSkill")); } auto CanvasPotencial() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanel_Potencial")); } auto CanvasDebuff() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanelDebuff")); } auto CanvasStatePalWork() const -> CanvasPanel { return WrapCanvas(STR("CanvasPanelStatePalWork")); } auto TextPalName() const -> TextBlock { return WrapText(STR("Text_PalName")); } auto TextLevel() const -> TextBlock { return WrapText(STR("Text_LevelValue")); } 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 TextMaxSanity() const -> TextBlock { return WrapText(STR("Text_MaxSanity")); } auto TextAttack() const -> TextBlock { return WrapText(STR("Text_AttackValue")); } auto TextDefense() const -> TextBlock { return WrapText(STR("Text_DefenseValue")); } auto TextWorkValue() const -> TextBlock { return WrapText(STR("Text_WorkValue")); } auto TextWorkTypeName() const -> TextBlock { return WrapText(STR("Text_WorkTypeName")); } auto TextNextExp() const -> TextBlock { return WrapText(STR("Text_NextExp")); } auto TextFriendshipRank() const -> TextBlock { return WrapText(STR("Text_FriendshipRank_Num")); } 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 CharacterIcon() const -> UObject* { return BoundObject(STR("WBP_PalCommonCharacterIcon")); } auto ElementIcon0() const -> UObject* { return BoundObject(STR("WBP_PalElementIcon")); } auto ElementIcon1() const -> UObject* { return BoundObject(STR("WBP_PalElementIcon_1")); } // ---- plain properties ---------------------------------------- auto SavedMaxHunger() const -> std::optional { return PropertyValue(STR("savedMaxHunger")); } auto SavedMaxSanity() const -> std::optional { return PropertyValue(STR("savedMaxSanity")); } auto HidePassive() const -> std::optional { return PropertyValue(STR("HidePassive")); } // ---- calls --------------------------------------------------- auto SetEmpty() -> bool { return CallVoid(STR("SetEmpty")); } auto SetupPartnerSkillInfo() -> bool { return CallVoid(STR("SetupPartnerSkillInfo")); } auto ToggleSkillInfo() -> bool { return CallVoid(STR("ToggleSKillInfo")); } // engine spelling auto OverrideHideTalent() -> bool { return CallVoid(STR("OverrideHideTalent")); } auto SetVisiblePartnerSkillInfo(bool bVisible) -> bool { struct P { bool bVisible; } p{ bVisible }; return Call(STR("SetVisiblePartnerSkillInfo"), p); } auto SetVisibleToggleSkillInfoKeyGuide(bool bVisible) -> bool { struct P { bool bVisible; } p{ bVisible }; return Call(STR("SetVisibleToggleSkillInfoKeyGuide"), p); } auto SetAwakening(bool bAwaked) -> bool { struct P { bool bAwaked; } p{ bAwaked }; return Call(STR("SetAwakening"), p); } auto SetImportedFlag(bool bImportedFlag) -> bool { struct P { bool bImportedFlag; } p{ bImportedFlag }; return Call(STR("SetImportedFlag"), p); } auto SetDetailMode(bool IsTip) -> bool { struct P { bool IsTip; } p{ IsTip }; return Call(STR("Set Detail Mode"), p); // the spaces are real } auto SetRarity(bool IsBoss, bool IsRare) -> bool { struct P { bool IsBoss; bool IsRare; } p{ IsBoss, IsRare }; return Call(STR("SetRarity"), p); } auto SetRank(int32 Rank) -> bool { struct P { int32 Rank; } p{ Rank }; return Call(STR("SetRank"), p); } auto SetSoulRank(int32 Rank) -> bool { struct P { int32 Rank; } p{ Rank }; return Call(STR("SetSoulRank"), p); } auto SetFoodAmount(int32 FoodAmount) -> bool { struct P { int32 FoodAmount; } p{ FoodAmount }; return Call(STR("SetFoodAmount"), p); } auto SetFriendShip(int32 FriendshipRank, int32 FriendshipPoint) -> bool { struct P { int32 FriendshipRank; int32 FriendshipPoint; } p{ FriendshipRank, FriendshipPoint }; return Call(STR("SetFriendShip"), p); } auto SetGender(EPalGenderType_ GenderType) -> bool { struct P { EPalGenderType_ GenderType; } p{ GenderType }; return Call(STR("SetGender"), p); } auto SetElementType(EPalElementType_ Type1, EPalElementType_ Type2) -> bool { struct P { EPalElementType_ type1; EPalElementType_ type2; } p{ Type1, Type2 }; return Call(STR("SetElementType"), p); } struct WorkSuitabilityCheck { bool bValid{}; EPalWorkSuitability_ Out{}; }; auto CheckValidWorkSuitability(EPalWorkSuitability_ In) -> std::optional { struct P { EPalWorkSuitability_ InWorkSuitability; bool IsValid; EPalWorkSuitability_ OutWorkSuitability; } p{ In, false, EPalWorkSuitability_::None }; if (!Call(STR("Check Valid Work Suitability"), p)) return std::nullopt; return WorkSuitabilityCheck{ p.IsValid, p.OutWorkSuitability }; } // ---- hook targets -------------------------------------------- static auto BindFromHandlePath() -> const TCHAR* { return STR("/Game/Pal/Blueprint/UI/UserInterface/IngameMenu/PalBox/WBP_IngameMenu_PalBox_PalDetail.WBP_IngameMenu_PalBox_PalDetail_C:BindFromHandle"); } static auto SetEmptyPath() -> const TCHAR* { return STR("/Game/Pal/Blueprint/UI/UserInterface/IngameMenu/PalBox/WBP_IngameMenu_PalBox_PalDetail.WBP_IngameMenu_PalBox_PalDetail_C:SetEmpty"); } static auto UpdateStatusParameterPath() -> const TCHAR* { return STR("/Game/Pal/Blueprint/UI/UserInterface/IngameMenu/PalBox/WBP_IngameMenu_PalBox_PalDetail.WBP_IngameMenu_PalBox_PalDetail_C:Update Status Parameter"); } struct BindFromHandleFrame { UObject* targetHandle; }; // UPalIndividualCharacterHandle* struct UpdateStatusParameterFrame { UObject* individualParam; }; // UPalIndividualCharacterParameter* private: auto WrapCanvas(const TCHAR* Name) const -> CanvasPanel { UObject* O = BoundObject(Name); return O ? CanvasPanel{ O } : CanvasPanel{}; } auto WrapText(const TCHAR* Name) const -> TextBlock { UObject* O = BoundObject(Name); return O ? TextBlock{ O } : TextBlock{}; } protected: PalDetailWidget(UObject* Obj, UClass* Expected, const TCHAR* Tag) : UserWidget(Obj, Expected, Tag) { } }; }