initial commit; cv 0.0.3

This commit is contained in:
2026-09-07 19:33:58 -04:00
commit abf065ddde
63 changed files with 8816 additions and 0 deletions

136
Api/Pal/PalCharacter.hpp Normal file
View File

@@ -0,0 +1,136 @@
#pragma once
#include <optional>
#include <Unreal/NameTypes.hpp>
#include <Api/UnrealWrapper.hpp>
#include "PalIndividual.hpp"
#include "PalTypes.hpp"
namespace PalUIExtension::Api::Pal
{
class PalCharacter : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalCharacter"); }
static auto DebugTag() -> const TCHAR* { return STR("PalCharacter"); }
PalCharacter() = default;
explicit PalCharacter(UObject* Obj) : UnrealWrapper(Obj, ClassOf<PalCharacter>(), DebugTag()) {}
// ---- components ------------------------------------------------
auto GetCharacterParameterComponent() -> UObject* { return ObjectGetter(STR("GetCharacterParameterComponent")); }
auto GetActionComponent() -> UObject* { return ObjectGetter(STR("GetActionComponent")); }
auto GetPalCharacterMovementComponent() -> UObject* { return ObjectGetter(STR("GetPalCharacterMovementComponent")); }
auto GetMainMesh() -> UObject* { return ObjectGetter(STR("GetMainMesh")); }
auto GetCurrentReservedMontage() -> UObject* { return ObjectGetter(STR("GetCurrentReservedMontage")); }
auto GetOverrideFaceMesh() -> UObject* { return ObjectGetter(STR("GetOverrideFaceMesh")); }
auto GetHandAttachMesh() -> UObject* { return ObjectGetter(STR("GetHandAttachMesh")); }
// ---- identity --------------------------------------------------
auto GetIndividualParameterObject() -> UObject*
{
UObject* Comp = GetCharacterParameterComponent();
if (!Comp) return nullptr;
LooseObject C{ Comp, STR("PalCharacterParameterComponent") };
return C.CallForReturn<UObject*>(STR("GetIndividualParameter")).value_or(nullptr);
}
auto Identify() -> PalIdentity
{
return PalIndividual::IdentifyFromParameter(GetIndividualParameterObject());
}
auto CharacterId() -> std::optional<FName>
{
return PalIndividual::CharacterId(GetIndividualParameterObject());
}
auto BlueprintClassName() const -> std::optional<StringType>
{
if (!m_obj) return std::nullopt;
UClass* Cls = m_obj->GetClassPrivate();
if (!Cls) return std::nullopt;
return Cls->GetName();
}
// ---- state queries ---------------------------------------------
auto IsInitialized() -> std::optional<bool> { return CallForReturn<bool>(STR("IsInitialized")); }
auto IsPart() -> std::optional<bool> { return CallForReturn<bool>(STR("IsPart")); }
auto IsCooping() -> std::optional<bool> { return CallForReturn<bool>(STR("IsCooping")); }
auto IsPreCooping() -> std::optional<bool> { return CallForReturn<bool>(STR("IsPreCooping")); }
auto IsLocalHiddenForCutscene() -> std::optional<bool> { return CallForReturn<bool>(STR("IsLocalHiddenForCutscene")); }
auto IsUseCustomAutoAimTarget() -> std::optional<bool> { return CallForReturn<bool>(STR("IsUseCustomAutoAimTarget")); }
auto IsAllActiveSkillCooldownFinished() -> std::optional<bool> { return CallForReturn<bool>(STR("IsAllActiveSkillCooldownFinished")); }
auto GetBattleMode() -> std::optional<bool> { return CallForReturn<bool>(STR("GetBattleMode")); }
auto GetTalkMode() -> std::optional<bool> { return CallForReturn<bool>(STR("GetTalkMode")); }
auto GetActiveActorFlag() -> std::optional<bool> { return CallForReturn<bool>(STR("GetActiveActorFlag")); }
auto IsActiveSkillCooldownFinished(EPalWazaID_ WazaID) -> std::optional<bool>
{
struct P { EPalWazaID_ WazaID; bool ReturnValue; } p{ WazaID, false };
return CallForReturn(STR("IsActiveSkillCooldownFinished"), p, &P::ReturnValue);
}
// ---- local-only mutators ---------------------------------------
auto ForceResetJumpState() -> bool { return CallVoid(STR("ForceResetJumpState")); }
auto RequestJump() -> bool { return CallVoid(STR("RequestJump")); }
auto ResetTickInterval() -> bool { return CallVoid(STR("ResetTickInterval")); }
auto LocalInitialized() -> bool { return CallVoid(STR("LocalInitialized")); }
auto RefreshDungeonLightingChannels() -> bool { return CallVoid(STR("RefreshDungeonLightingChannels")); }
auto RequestExecuteTickNextFrameForAction() -> bool { return CallVoid(STR("RequestExecuteTickNextFrameForAction")); }
auto BroadcastOnCompleteInitializeParameter() -> bool { return CallVoid(STR("BroadcastOnCompleteInitializeParameter")); }
auto UpdateGroundRayCast(bool bImmediateApply) -> bool
{
struct P { bool bImmediateApply; } p{ bImmediateApply };
return Call(STR("UpdateGroundRayCast"), p);
}
auto SetVisibleCharacterMesh(bool Active) -> bool
{
struct P { bool Active; } p{ Active };
return Call(STR("SetVisibleCharacterMesh"), p);
}
auto SetVisibleHandAttachMesh(bool Active) -> bool
{
struct P { bool Active; } p{ Active };
return Call(STR("SetVisibleHandAttachMesh"), p);
}
auto SetLocalHiddenForCutscene(bool bHide) -> bool
{
struct P { bool bHide; } p{ bHide };
return Call(STR("SetLocalHiddenForCutscene"), p);
}
auto SetActiveCollisionMovement(bool Active) -> bool
{
struct P { bool Active; } p{ Active };
return Call(STR("SetActiveCollisionMovement"), p);
}
auto ChangeBattleModeFlag(bool IsBattle) -> bool
{
struct P { bool IsBattle; } p{ IsBattle };
return Call(STR("ChangeBattleModeFlag"), p);
}
auto SetDisableChangeIntervalByImportance(FName FlagName, bool bIsDisable) -> bool
{
struct P { FName flagName; bool isDisable; } p{ FlagName, bIsDisable };
return Call(STR("SetDisableChangeIntervalByImportance"), p);
}
private:
auto ObjectGetter(const TCHAR* FunctionName) -> UObject*
{
struct P { UObject* ReturnValue; } p{ nullptr };
auto Result = CallForReturn(FunctionName, p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
};
}

View File

@@ -0,0 +1,369 @@
#pragma once
#include <optional>
#include <Unreal/FText.hpp>
#include <Unreal/NameTypes.hpp>
#include <Api/UnrealWrapper.hpp>
#include <Static/LogGate.hpp>
#include "PalIndividual.hpp"
#include "PalTypes.hpp"
namespace PalUIExtension::Api::Pal
{
class PalDatabaseCharacterParameter : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalDatabaseCharacterParameter"); }
static auto DebugTag() -> const TCHAR* { return STR("PalDatabase"); }
PalDatabaseCharacterParameter() = default;
explicit PalDatabaseCharacterParameter(UObject* Obj) : UnrealWrapper(Obj, ClassOf<PalDatabaseCharacterParameter>(), DebugTag()) {}
static auto StripVariantPrefix(FName CharacterId) -> std::optional<FName>
{
const StringType Id = CharacterId.ToString();
static const StringType Prefixes[] = {
STR("BOSS_"), STR("PREDATOR_"), STR("RAID_"), STR("GYM_"),
};
for (const StringType& Prefix : Prefixes)
{
if (Id.size() <= Prefix.size()) continue;
if (!StartsWithNoCase(Id, Prefix)) continue;
return FName(StringViewType(Id).substr(Prefix.size()), FNAME_Add);
}
return std::nullopt;
}
static auto ResolveBaseRowName(FName CharacterId) -> FName
{
return StripVariantPrefix(CharacterId).value_or(CharacterId);
}
// ---- row lookups by species FName -----------------------------
auto GetZukanIndex(FName RowName) -> std::optional<int32>
{
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
return CallForReturn(STR("GetZukanIndex"), p, &P::ReturnValue);
}
auto GetZukanIndexResolved(FName CharacterId) -> std::optional<int32>
{
if (auto Direct = GetZukanIndex(CharacterId); Direct.has_value() && *Direct > 0)
{
return Direct;
}
auto Base = StripVariantPrefix(CharacterId);
if (!Base.has_value()) return std::nullopt;
auto Fallback = GetZukanIndex(*Base);
if (!Fallback.has_value() || *Fallback <= 0) return std::nullopt;
if constexpr (Static::kVerboseLogging)
{
Output::send<LogLevel::Verbose>(
STR("[PalDatabase] ZukanIndex: '{}' had none, resolved via base '{}' -> {}\n"),
CharacterId.ToString(), Base->ToString(), *Fallback);
}
return Fallback;
}
auto GetLocalizedBaseCharacterName(FName CharacterId) -> std::optional<FText>
{
return GetLocalizedCharacterName(ResolveBaseRowName(CharacterId));
}
auto GetTribe(FName RowName) -> std::optional<EPalTribeID_>
{
struct P { FName RowName; EPalTribeID_ ReturnValue; } p{ RowName, 0 };
return CallForReturn(STR("GetTribe"), p, &P::ReturnValue);
}
auto GetSize(FName RowName) -> std::optional<EPalSizeType_>
{
struct P { FName RowName; EPalSizeType_ ReturnValue; } p{ RowName, EPalSizeType_::None };
return CallForReturn(STR("GetSize"), p, &P::ReturnValue);
}
auto GetGenusCategory(FName RowName) -> std::optional<EPalGenusCategoryType_>
{
struct P { FName RowName; EPalGenusCategoryType_ ReturnValue; } p{ RowName, EPalGenusCategoryType_::None };
return CallForReturn(STR("GetGenusCategory"), p, &P::ReturnValue);
}
auto GetOrganizationType(FName RowName) -> std::optional<EPalOrganizationType_>
{
struct P { FName RowName; EPalOrganizationType_ ReturnValue; } p{ RowName, EPalOrganizationType_::None };
return CallForReturn(STR("GetOrganizationType"), p, &P::ReturnValue);
}
auto GetWeaponType(FName RowName) -> std::optional<EPalWeaponType_>
{
struct P { FName RowName; EPalWeaponType_ ReturnValue; } p{ RowName, EPalWeaponType_::None };
return CallForReturn(STR("GetWeaponType"), p, &P::ReturnValue);
}
auto GetBattleBGM(FName RowName) -> std::optional<EPalBattleBGMType_>
{
struct P { FName RowName; EPalBattleBGMType_ ReturnValue; } p{ RowName, EPalBattleBGMType_::None };
return CallForReturn(STR("GetBattleBGM"), p, &P::ReturnValue);
}
auto GetPalAwakeningItemElement(FName ItemId) -> std::optional<EPalElementType_>
{
struct P { FName ItemId; EPalElementType_ ReturnValue; } p{ ItemId, EPalElementType_::None };
return CallForReturn(STR("GetPalAwakeningItemElement"), p, &P::ReturnValue);
}
struct ElementTypePair { EPalElementType_ Primary{}; EPalElementType_ Secondary{}; };
// void return, two out-params -- not CallForReturn's shape.
auto GetElementType(FName RowName) -> std::optional<ElementTypePair>
{
struct P { FName RowName; EPalElementType_ Element1; EPalElementType_ Element2; }
p{ RowName, EPalElementType_::None, EPalElementType_::None };
if (!Call(STR("GetElementType"), p)) return std::nullopt;
return ElementTypePair{ p.Element1, p.Element2 };
}
// void return, one out-param.
auto GetBestWorkSuitability(FName RowName) -> std::optional<EPalWorkSuitability_>
{
struct P { FName RowName; EPalWorkSuitability_ BestWorkSuitability; }
p{ RowName, EPalWorkSuitability_::None };
if (!Call(STR("GetBestWorkSuitability"), p)) return std::nullopt;
return p.BestWorkSuitability;
}
auto GetWeaponEquip(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetWeaponEquip"), p, &P::ReturnValue);
}
auto GetUseBossHPGauge(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetUseBossHPGauge"), p, &P::ReturnValue);
}
auto GetNocturnal(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetNocturnal"), p, &P::ReturnValue);
}
auto GetIsTowerBoss(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetIsTowerBoss"), p, &P::ReturnValue);
}
auto GetIsRaidBoss(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetIsRaidBoss"), p, &P::ReturnValue);
}
auto GetIsPredatorBoss(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetIsPredatorBoss"), p, &P::ReturnValue);
}
auto GetIsPal(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetIsPal"), p, &P::ReturnValue);
}
auto GetIsLegend(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetIsLegend"), p, &P::ReturnValue);
}
auto GetIsBoss(FName RowName) -> std::optional<bool>
{
struct P { FName RowName; bool ReturnValue; } p{ RowName, false };
return CallForReturn(STR("GetIsBoss"), p, &P::ReturnValue);
}
auto IsArenaUnusableItem(FName ItemId) -> std::optional<bool>
{
struct P { FName ItemId; bool ReturnValue; } p{ ItemId, false };
return CallForReturn(STR("IsArenaUnusableItem"), p, &P::ReturnValue);
}
auto GetViewingDistance_cm(FName RowName) -> std::optional<int32>
{
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
return CallForReturn(STR("GetViewingDistance_cm"), p, &P::ReturnValue);
}
auto GetViewingAngle_Degree(FName RowName) -> std::optional<int32>
{
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
return CallForReturn(STR("GetViewingAngle_Degree"), p, &P::ReturnValue);
}
auto GetRarity(FName RowName) -> std::optional<int32>
{
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
return CallForReturn(STR("GetRarity"), p, &P::ReturnValue);
}
auto GetFoodAmount(FName RowName) -> std::optional<int32>
{
struct P { FName RowName; int32 ReturnValue; } p{ RowName, 0 };
return CallForReturn(STR("GetFoodAmount"), p, &P::ReturnValue);
}
auto GetPriceRate(FName RowName) -> std::optional<float>
{
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
return CallForReturn(STR("GetPriceRate"), p, &P::ReturnValue);
}
auto GetHearingRate(FName RowName) -> std::optional<float>
{
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
return CallForReturn(STR("GetHearingRate"), p, &P::ReturnValue);
}
auto GetExpRatio(FName RowName) -> std::optional<float>
{
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
return CallForReturn(STR("GetExpRatio"), p, &P::ReturnValue);
}
auto GetCaptureRateCorrect(FName RowName) -> std::optional<float>
{
struct P { FName RowName; float ReturnValue; } p{ RowName, 0.f };
return CallForReturn(STR("GetCaptureRateCorrect"), p, &P::ReturnValue);
}
auto GetBPClassName(FName RowName) -> std::optional<FName>
{
struct P { FName RowName; FName ReturnValue; } p{ RowName, {} };
return CallForReturn(STR("GetBPClassName"), p, &P::ReturnValue);
}
auto GetFirstDefeatRewardItemID(FName CharacterID) -> std::optional<FName>
{
struct P { FName CharacterID; FName ReturnValue; } p{ CharacterID, {} };
return CallForReturn(STR("GetFirstDefeatRewardItemID"), p, &P::ReturnValue);
}
// void return, FName out-param -- not a FString, no ownership question, just an index pair like every other FName here.
auto GetPrefixNameMsgID(FName CharacterID) -> std::optional<FName>
{
struct P { FName CharacterID; FName OutMsgID; } p{ CharacterID, {} };
if (!Call(STR("GetPrefixNameMsgID"), p)) return std::nullopt;
return p.OutMsgID;
}
auto GetLocalizedCharacterName(FName CharacterID) -> std::optional<FText>
{
struct P { FName CharacterID; FText OutText; } p{ CharacterID, {} };
if (!Call(STR("GetLocalizedCharacterName"), p)) return std::nullopt;
return p.OutText;
}
auto GetLocalizedUniqueNPCName(FName UniqueNPCID) -> std::optional<FText>
{
struct P { FName UniqueNPCID; FText OutText; } p{ UniqueNPCID, {} };
if (!Call(STR("GetLocalizedUniqueNPCName"), p)) return std::nullopt;
return p.OutText;
}
// ---- friendship ------------------------------------------------
auto GetMinFriendshipRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMinFriendshipRank")); }
auto GetMaxFriendshipRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMaxFriendshipRank")); }
auto GetFriendshipRank(int32 FriendshipPoint) -> std::optional<int32>
{
struct P { int32 FriendshipPoint; int32 ReturnValue; } p{ FriendshipPoint, 0 };
return CallForReturn(STR("GetFriendshipRank"), p, &P::ReturnValue);
}
auto CalcFriendshipProgress(int32 FriendshipPoint) -> std::optional<float>
{
struct P { int32 FriendshipPoint; float ReturnValue; } p{ FriendshipPoint, 0.f };
return CallForReturn(STR("CalcFriendshipProgress"), p, &P::ReturnValue);
}
// bool return + int32& out-param.
auto GetFriendshipRequiredPointByRank(int32 FriendshipRank) -> std::optional<int32>
{
struct P { int32 FriendshipRank; int32 OutRequiredPoint; bool ReturnValue; }
p{ FriendshipRank, 0, false };
if (!Call(STR("GetFriendshipRequiredPointByRank"), p) || !p.ReturnValue) return std::nullopt;
return p.OutRequiredPoint;
}
// ---- derived from a live UPalIndividualCharacterParameter* ---------
auto GetHP(UObject* IndividualParameter) -> std::optional<int32>
{
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
return CallForReturn(STR("GetHP"), p, &P::ReturnValue);
}
auto GetMeleeAttack(UObject* IndividualParameter) -> std::optional<int32>
{
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
return CallForReturn(STR("GetMeleeAttack"), p, &P::ReturnValue);
}
auto GetShotAttack(UObject* IndividualParameter) -> std::optional<int32>
{
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
return CallForReturn(STR("GetShotAttack"), p, &P::ReturnValue);
}
auto GetDefense(UObject* IndividualParameter) -> std::optional<int32>
{
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
return CallForReturn(STR("GetDefense"), p, &P::ReturnValue);
}
auto GetCraftSpeed(UObject* IndividualParameter) -> std::optional<int32>
{
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
return CallForReturn(STR("GetCraftSpeed"), p, &P::ReturnValue);
}
auto GetSupport(UObject* IndividualParameter) -> std::optional<int32>
{
struct P { UObject* IndividualParameter; int32 ReturnValue; } p{ IndividualParameter, 0 };
return CallForReturn(STR("GetSupport"), p, &P::ReturnValue);
}
auto HigherLevelOtomoFromTrainer(UObject* IndividualCharacterParameter) -> std::optional<int32>
{
struct P { UObject* IndividualCharacterParameter; int32 ReturnValue; } p{ IndividualCharacterParameter, 0 };
return CallForReturn(STR("HigherLevelOtomoFromTrainer"), p, &P::ReturnValue);
}
auto UpdateApplyDatabaseToIndividualParameter(UObject* IndividualParameter) -> bool
{
struct P { UObject* IndividualParameter; } p{ IndividualParameter };
return Call(STR("UpdateApplyDatabaseToIndividualParameter"), p);
}
// Raw UObject* return -- UPalPettingPresset isn't modeled anywhere
auto GetPettingPreset() -> UObject*
{
struct P { UObject* ReturnValue; } p{ nullptr };
auto Result = CallForReturn(STR("GetPettingPreset"), p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
// WorldContextObject is a plain UObject* at the native signature
// level -- the meta=(WorldContext=...) annotation only affects
// the Blueprint editor node, not the ProcessEvent frame. Pass
// any live UObject with a valid world (a player controller, an
// actor, etc.).
auto CalcCorrectedLevel(int32 TrainerLevel, int32 TargetCharacterLevel, UObject* WorldContextObject) -> std::optional<int32>
{
struct P { int32 TrainerLevel; int32 TargetCharacterLevel; UObject* WorldContextObject; int32 ReturnValue; }
p{ TrainerLevel, TargetCharacterLevel, WorldContextObject, 0 };
return CallForReturn(STR("CalcCorrectedLevel"), p, &P::ReturnValue);
}
private:
static auto StartsWithNoCase(const StringType& Str, const StringType& Prefix) -> bool
{
if (Str.size() < Prefix.size()) return false;
for (size_t i = 0; i < Prefix.size(); ++i)
{
CharType A = Str[i];
CharType B = Prefix[i];
if (A >= STR('a') && A <= STR('z')) A = static_cast<CharType>(A - STR('a') + STR('A'));
if (B >= STR('a') && B <= STR('z')) B = static_cast<CharType>(B - STR('a') + STR('A'));
if (A != B) return false;
}
return true;
}
};
}

301
Api/Pal/PalGameMode.hpp Normal file
View File

@@ -0,0 +1,301 @@
#pragma once
#include <optional>
#include <Unreal/FString.hpp>
#include <Unreal/NameTypes.hpp>
#include <Api/UnrealWrapper.hpp>
namespace PalUIExtension::Api::Pal
{
using namespace RC;
using namespace RC::Unreal;
// ==================================================================
// EPalGameModeType -- confirmed from the dump, UENUM(BlueprintType)
// over uint8, two values. Mirrored here for the same reason
// ESlateVisibility_ is: a params struct needs a concrete type of the
// right width, and pulling in the game's generated header is not an
// option.
// ==================================================================
enum class EPalGameModeType_ : uint8
{
Title = 0,
InGame = 1,
};
// ==================================================================
// APalGameModeBase.
//
// Two things exist on this class and one of them matters:
// GameModeType, an FEnumProperty over uint8. Read it to tell the
// title screen apart from a live world without inspecting the map
// name.
//
// ---- THE THING TO INTERNALISE ABOUT GAME MODES -------------------
//
// A GameMode exists ONLY ON THE AUTHORITY. On a listen host and in
// single-player that is the local process, so this class is
// reachable. On a client connected to a dedicated server, no
// APalGameMode is ever instantiated locally and nothing in this file
// will ever resolve to anything.
//
// That is not a limitation of this wrapper, it is what a game mode
// IS, and it decides what you may and may not build on top of it. A
// client-side UI mod that depends on a game-mode hook for
// correctness is broken for every dedicated-server player. Use these
// as a supplement to an engine-level signal, never as the only one.
// ==================================================================
class PalGameModeBase : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalGameModeBase"); }
static auto DebugTag() -> const TCHAR* { return STR("PalGameModeBase"); }
PalGameModeBase() = default;
explicit PalGameModeBase(UObject* Obj)
: UnrealWrapper(Obj, ClassOf<PalGameModeBase>(), DebugTag()) {}
// FEnumProperty over uint8 -- GetSize() reports 1, and
// EPalGameModeType_ is 1 byte, so the size check in PropertyPtr is
// meaningful here rather than vacuous.
auto GameModeType() const -> std::optional<EPalGameModeType_>
{
return PropertyValue<EPalGameModeType_>(STR("GameModeType"));
}
auto IsInGame() const -> bool
{
const auto T = GameModeType();
return T.has_value() && *T == EPalGameModeType_::InGame;
}
auto IsTitle() const -> bool
{
const auto T = GameModeType();
return T.has_value() && *T == EPalGameModeType_::Title;
}
protected:
PalGameModeBase(UObject* Obj, UClass* Expected, const TCHAR* Tag)
: UnrealWrapper(Obj, Expected, Tag) {}
};
// ==================================================================
// APalGameMode -- the in-world game mode.
//
// ---- WHAT IS WORTH HOOKING HERE, AND WHAT IS NOT -----------------
//
// RestartGame is the one this tree cares about: it is the game
// deciding the current world is finished, fired BEFORE the travel
// that destroys it. That ordering is the whole value -- a cache of
// widget pointers wants to be dropped while those pointers are still
// merely useless, not after they are dangling.
//
// READ THE CAVEAT BLOCK ON RestartGamePath() BEFORE RELYING ON IT.
// It has two failure modes that are invisible in testing if you only
// test single-player.
//
// The session/auth callbacks (OnUpdateSession, OnCompleteAuth,
// OnCompleteCreateSession, OnEOSLoginDedicatedServerComplete) are
// dedicated-server plumbing. They are wrapped as PATHS ONLY, with
// frames, because they are occasionally useful for diagnosing "why
// did my server mod not initialise" -- but nothing in a client-side
// UI mod should be reading them, and none of them fire in
// single-player at all.
//
// ---- WHY THERE IS NO Current() -----------------------------------
//
// The obvious convenience -- a static that hands back the live game
// mode -- is deliberately absent. Every way to get one without a
// UWorld in hand goes through UObjectGlobals::FindObject or
// FindObjects, and for a Blueprint-reachable native class that is a
// linear walk of the entire GUObjectArray (see the note in
// PalBoxNightWorkIndicator on what that cost actually is). A helper
// that looks like a property read and is really a million-object scan
// is the kind of convenience that ends up on a per-frame path.
//
// Get the instance from a hook that already has it instead: every
// callback below receives it as Ctx.Context, and
// Hook::RegisterInitGameStatePostCallback hands over an
// AGameModeBase* directly at world start.
// ==================================================================
class PalGameMode : public PalGameModeBase
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalGameMode"); }
static auto DebugTag() -> const TCHAR* { return STR("PalGameMode"); }
PalGameMode() = default;
explicit PalGameMode(UObject* Obj)
: PalGameModeBase(Obj, ClassOf<PalGameMode>(), DebugTag()) {}
// ---- properties ------------------------------------------------
// APlayerStart*. No wrapper for it in this tree, so the raw
// pointer is the honest return type.
auto CachePlayerStart() const -> UObject*
{
return TryObjectProperty(STR("CachePlayerStart"));
}
// ==============================================================
// HOOK TARGETS
// ==============================================================
// ==============================================================
// RestartGame. READ THIS BEFORE BUILDING ON IT.
//
// Two failure modes, both silent, both invisible if you only
// test single-player:
//
// 1. AUTHORITY ONLY. No APalGameMode is instantiated on a client
// connected to a dedicated server, so this hook never installs
// and never fires there. For a client-side UI mod that is the
// majority multiplayer case.
//
// 2. REFLECTION ONLY. This is a native UFUNCTION(BlueprintCallable).
// UE4SS hooks UFunction execution, which catches invocations
// that go through ProcessEvent -- a Blueprint node, a console
// exec, a reflected call. It does NOT catch native C++ code
// calling APalGameMode::RestartGame() directly, because that
// path never touches the reflection system. Whether Palworld
// restarts via Blueprint or via C++ is not answerable from a
// header dump; it has to be observed.
//
// The practical consequence: treat a RestartGame callback as an
// OPPORTUNISTIC EARLY WARNING, not as the teardown signal. The
// load-bearing one is Hook::RegisterLoadMapPreCallback, which is
// engine-level, fires on every map transition regardless of what
// triggered it, and works identically on clients and hosts.
//
// Wiring both is correct and costs nothing: teardown must be
// idempotent anyway, since a restart that goes through both paths
// will call it twice.
// ==============================================================
static auto RestartGamePath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:RestartGame");
}
static auto InitDedicatedServerPath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:InitDedicatedServer");
}
static auto OnServerLobbyUpdatePath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:OnServerLobbyUpdate");
}
static auto OnUpdateSessionPath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:OnUpdateSession");
}
static auto OnCompleteAuthPath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:OnCompleteAuth");
}
static auto OnCompleteCreateSessionPath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:OnCompleteCreateSession");
}
static auto OnEOSLoginDedicatedServerCompletePath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:OnEOSLoginDedicatedServerComplete");
}
static auto CreateSessionPath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:CreateSession");
}
static auto FindPlayerStartWithTagPath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameMode:FindPlayerStartWithTag");
}
// ---- frames ---------------------------------------------------
//
// Leading parameters only, matching the convention in
// PalCommonCharacterSlot.hpp: hook frames are NOT size-checked, so
// reading past the declared parameters reads engine locals. On a
// PRE hook those are uninitialised.
//
// The FString members are the part to be careful with. A
// `const FString&` UFUNCTION parameter still occupies a full
// FString in the frame (TArray<TCHAR>: 8-byte data pointer +
// int32 Num + int32 Max = 16 bytes), so the layout below is what
// the engine writes. It is NOT owned by you -- read it, do not
// move from it, do not free it.
//
// RestartGame takes nothing, which is why there is no frame for
// it and why its callback should not call Ctx.GetParams at all.
struct HttpResponseFrame
{
FString ResponseBody; // 0x00
bool bResponseOK; // 0x10
int32 ResponseCode; // 0x14 (after 3 bytes of padding)
};
struct EOSLoginCompleteFrame
{
UObject* UserInfo; // 0x00 const UPocketpairUserInfo*
bool bSuccess; // 0x08
FString ErrorStr; // 0x10 (after 7 bytes of padding)
};
struct CreateSessionFrame { FString Address; };
struct FindPlayerStartWithTagFrame { FName Tag; UObject* ReturnValue; };
protected:
PalGameMode(UObject* Obj, UClass* Expected, const TCHAR* Tag)
: PalGameModeBase(Obj, Expected, Tag) {}
};
// ==================================================================
// APalGameModeLogin -- the title-screen game mode.
//
// Included because it is the OTHER half of the world-lifecycle
// picture and it is easy to forget it exists: going from a save back
// to the title is a map transition into THIS game mode, not a
// RestartGame on the previous one. If teardown only fires on
// APalGameMode, quitting to title leaves every cached pointer alive
// and dangling.
//
// GoToTitle is BlueprintImplementableEvent -- no native body. It
// dispatches through the object's class chain like anything else, so
// it is hookable, but if no Blueprint subclass overrides it there is
// nothing to hook and the registry will defer forever.
// ==================================================================
class PalGameModeLogin : public PalGameModeBase
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalGameModeLogin"); }
static auto DebugTag() -> const TCHAR* { return STR("PalGameModeLogin"); }
PalGameModeLogin() = default;
explicit PalGameModeLogin(UObject* Obj)
: PalGameModeBase(Obj, ClassOf<PalGameModeLogin>(), DebugTag()) {}
static auto OnCompletePath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameModeLogin:OnComplete");
}
static auto GoToTitlePath() -> const TCHAR*
{
return STR("/Script/Pal.PalGameModeLogin:GoToTitle");
}
struct OnCompleteFrame { bool bCanPlayMulti; };
protected:
PalGameModeLogin(UObject* Obj, UClass* Expected, const TCHAR* Tag)
: PalGameModeBase(Obj, Expected, Tag) {}
};
}

127
Api/Pal/PalIndividual.hpp Normal file
View File

@@ -0,0 +1,127 @@
#pragma once
#include <optional>
#include <cstring>
#include <Unreal/FText.hpp>
#include <Unreal/NameTypes.hpp>
#include <Api\UmgTypes.hpp>
#include <Api\UnrealWrapper.hpp>
#include "PalTypes.hpp"
namespace PalUIExtension::Api::Pal
{
enum class EPalGenderType_ : uint8 { None = 0, Male = 1, Female = 2 };
enum class EPalElementType_ : uint8
{
None = 0, Normal = 1, Fire = 2, Water = 3, Leaf = 4,
Electricity = 5, Ice = 6, Earth = 7, Dark = 8, Dragon = 9, MAX = 10,
};
enum class EPalWorkSuitability_ : uint8
{
None = 0, EmitFlame = 1, Watering = 2, Seeding = 3,
GenerateElectricity = 4, Handcraft = 5, Collection = 6, Deforest = 7,
Mining = 8, OilExtraction = 9, ProductMedicine = 10, Cool = 11,
Transport = 12, MonsterFarm = 13, Anyone = 14, MAX = 15,
};
class LooseObject : public UnrealWrapper
{
public:
LooseObject() = default;
explicit LooseObject(UObject* Obj, const TCHAR* Tag = STR("Loose"))
: UnrealWrapper(Obj, UncheckedTag{}, Tag) {
}
using UnrealWrapper::Call;
using UnrealWrapper::CallVoid;
using UnrealWrapper::CallForReturn;
using UnrealWrapper::PropertyPtr;
using UnrealWrapper::PropertyValue;
};
// this struct is now redundant. watch it never get removed.
struct FPalInstanceID {
FGuid_ PlayerUID;
FGuid_ InstanceID;
FString DebugName;
};
struct PalIdentity
{
UObject* Handle{};
UObject* IndividualParameter{};
std::optional<FName> CharacterId; // the species. "SheepBall", etc.
std::optional<int32> Level;
std::optional<int32> Rank;
std::optional<EPalGenderType_> Gender;
std::optional<bool> bRare;
explicit operator bool() const { return CharacterId.has_value(); }
};
class PalIndividual
{
public:
static auto ParameterFromHandle(UObject* Handle) -> UObject*
{
if (!Handle) return nullptr;
LooseObject H{ Handle, STR("PalIndividualCharacter") };
return H.CallForReturn<UObject*>(STR("TryGetIndividualParameter")).value_or(nullptr);
}
static auto CharacterId(UObject* Parameter) -> std::optional<FName>
{
if (!Parameter) return std::nullopt;
LooseObject P{ Parameter, STR("PalIndividualCharacterParameter") };
return P.CallForReturn<FName>(STR("GetCharacterID"));
}
static auto CharacterIdFromHandle(UObject* Handle) -> std::optional<FName>
{
return CharacterId(ParameterFromHandle(Handle));
}
static auto IdentifyFromParameter(UObject* Parameter) -> PalIdentity
{
PalIdentity Out{};
Out.IndividualParameter = Parameter;
if (!Parameter) return Out;
LooseObject P{ Parameter, STR("PalIndividualCharacterParameter") };
Out.CharacterId = P.CallForReturn<FName>(STR("GetCharacterID"));
Out.Level = P.CallForReturn<int32>(STR("GetLevel"));
Out.Rank = P.CallForReturn<int32>(STR("GetRank"));
Out.Gender = P.CallForReturn<EPalGenderType_>(STR("GetGenderType"));
Out.bRare = P.CallForReturn<bool>(STR("IsRarePal"));
return Out;
}
static auto Identify(UObject* Handle) -> PalIdentity
{
PalIdentity Out = IdentifyFromParameter(ParameterFromHandle(Handle));
Out.Handle = Handle;
return Out;
}
static auto GetInstanceIds(UObject* Handle) -> std::optional<FPalInstanceID>
{
if (!Handle) return std::nullopt;
// FPalInstanceID
LooseObject H{ Handle, STR("PalIndividualCharacterHandle") };
auto _Out = H.CallForReturn<FPalInstanceID>(STR("GetIndividualID"));
if (!_Out.has_value()) return std::nullopt;
return FPalInstanceID{ _Out.value().PlayerUID, _Out.value().InstanceID, _Out.value().DebugName };
}
};
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include <Api/UnrealWrapper.hpp>
#include "PalIndividual.hpp"
#include "PalCharacter.hpp"
namespace PalUIExtension::Api::Pal
{
class PalIndividualCharacterHandle : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalIndividualCharacterHandle"); }
static auto DebugTag() -> const TCHAR* { return STR("PalIndividualCharacterHandle"); }
PalIndividualCharacterHandle() = default;
explicit PalIndividualCharacterHandle(UObject* Obj) : UnrealWrapper(Obj, ClassOf<PalIndividualCharacterHandle>(), DebugTag()) {}
auto TryGetIndividualParameterObject() -> UObject*
{
struct P { UObject* ReturnValue; } p{ nullptr };
auto Result = CallForReturn(STR("TryGetIndividualParameter"), p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
auto TryGetIndividualActorObject() -> UObject*
{
struct P { UObject* ReturnValue; } p{ nullptr };
auto Result = CallForReturn(STR("TryGetIndividualActor"), p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
auto TryGetIndividualActor() -> PalCharacter
{
UObject* A = TryGetIndividualActorObject();
return A ? PalCharacter{ A } : PalCharacter{};
}
auto TryGetPhantomActor(int32 PhantomId) -> UObject*
{
struct P { int32 PhantomId; UObject* ReturnValue; } p{ PhantomId, nullptr };
auto Result = CallForReturn(STR("TryGetPhantomActor"), p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
auto GetPhantomIDByActor(UObject* Character) -> std::optional<int32>
{
struct P { UObject* Character; int32 ReturnValue; } p{ Character, 0 };
return CallForReturn(STR("GetPhantomIDByActor"), p, &P::ReturnValue);
}
auto GetInstanceIds() -> std::optional<FPalInstanceID>
{
return PalIndividual::GetInstanceIds(Get());
}
};
}

View File

@@ -0,0 +1,480 @@
#pragma once
#include <optional>
#include <Unreal/FText.hpp>
#include <Unreal/NameTypes.hpp>
#include <Api/UnrealWrapper.hpp>
#include "PalIndividual.hpp"
#include "PalTypes.hpp"
namespace PalUIExtension::Api::Pal
{
class PalIndividualCharacterParameter : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalIndividualCharacterParameter"); }
static auto DebugTag() -> const TCHAR* { return STR("PalIndividualCharacterParameter"); }
PalIndividualCharacterParameter() = default;
explicit PalIndividualCharacterParameter(UObject* Obj) : UnrealWrapper(Obj, ClassOf<PalIndividualCharacterParameter>(), DebugTag()) {}
// ---- identity ---------------------------------------------------
auto GetCharacterID() -> std::optional<FName> { return CallForReturn<FName>(STR("GetCharacterID")); }
auto GetUniqueNPCID() -> std::optional<FName> { return CallForReturn<FName>(STR("GetUniqueNPCID")); }
auto GetSkinName() -> std::optional<FName> { return CallForReturn<FName>(STR("GetSkinName")); }
auto GetGenderType() -> std::optional<EPalGenderType_>
{
return CallForReturn<EPalGenderType_>(STR("GetGenderType"));
}
auto GetTribeID() -> std::optional<EPalTribeID_>
{
return CallForReturn<EPalTribeID_>(STR("GetTribeID"));
}
auto IsRarePal() -> std::optional<bool> { return CallForReturn<bool>(STR("IsRarePal")); }
auto IsFavoritePal() -> std::optional<bool> { return CallForReturn<bool>(STR("IsFavoritePal")); }
auto GetFavoriteIndex() -> std::optional<int32> { return CallForReturn<int32>(STR("GetFavoriteIndex")); }
auto IsSkinApplied() -> std::optional<bool> { return CallForReturn<bool>(STR("IsSkinApplied")); }
auto GetSkinAppliedCharacterId() -> std::optional<FGuid_>
{
return CallForReturn<FGuid_>(STR("GetSkinAppliedCharacterId"));
}
auto GetPalId() -> std::optional<FPalInstanceID>
{
struct P { alignas(8) uint8 Frame[48]; } p{}; // FPalInstanceID
if (!Call(STR("GetPalId"), p)) return std::nullopt;
FPalInstanceID Out{};
std::memcpy(&Out, p.Frame, sizeof(Out));
return Out;
}
// Nickname getters
auto GetNickname() -> std::optional<FString>
{
struct P { FString OutName; } p{};
if (!Call(STR("GetNickname"), p)) return std::nullopt;
return p.OutName;
}
auto GetNickNameWithOnlineID() -> std::optional<FString>
{
struct P { FString OutName; } p{};
if (!Call(STR("GetNickNameWithOnlineID"), p)) return std::nullopt;
return p.OutName;
}
auto GetNickNameByCheckBlockedUser() -> std::optional<FString>
{
struct P { FString OutName; } p{};
if (!Call(STR("GetNickNameByCheckBlockedUser"), p)) return std::nullopt;
return p.OutName;
}
// ---- level / experience ------------------------------------------
auto GetLevel() -> std::optional<int32> { return CallForReturn<int32>(STR("GetLevel")); }
auto IsLevelMax() -> std::optional<bool> { return CallForReturn<bool>(STR("IsLevelMax")); }
auto GetExp() -> std::optional<int64> { return CallForReturn<int64>(STR("GetExp")); }
auto GetRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetRank")); }
auto GetRankUpExp() -> std::optional<int32> { return CallForReturn<int32>(STR("GetRankUpExp")); }
auto GetPalSoulRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetPalSoulRank")); }
auto IsOverrideLevel() -> std::optional<bool> { return CallForReturn<bool>(STR("IsOverrideLevel")); }
auto GetOverrideLevel() -> std::optional<int32> { return CallForReturn<int32>(STR("GetOverrideLevel")); }
auto SetOverrideLevel(int32 OverrideLevel) -> bool
{
struct P { int32 OverrideLevel; } p{ OverrideLevel };
return Call(STR("SetOverrideLevel"), p);
}
// ---- HP / shield / death -----------------------------------------
auto GetHP() -> std::optional<FFixedPoint64_> { return CallForReturn<FFixedPoint64_>(STR("GetHP")); }
auto GetMaxHP_withBuff() -> std::optional<FFixedPoint64_> { return CallForReturn<FFixedPoint64_>(STR("GetMaxHP_withBuff")); }
auto GetMaxHP() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMaxHP")); }
auto GetHPRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetHPRank")); }
auto GetShieldHP() -> std::optional<FFixedPoint64_> { return CallForReturn<FFixedPoint64_>(STR("GetShieldHP")); }
auto GetShieldMaxHP() -> std::optional<FFixedPoint64_> { return CallForReturn<FFixedPoint64_>(STR("GetShieldMaxHP")); }
auto GetCurrentPhaseHPLimit() -> std::optional<FFixedPoint64_>
{
struct P { FFixedPoint64_ OutPhaseHPLimit; bool ReturnValue; } p{ {}, false };
auto Result = CallForReturn(STR("GetCurrentPhaseHPLimit"), p, &P::ReturnValue);
if (!Result || !*Result) return std::nullopt;
return p.OutPhaseHPLimit;
}
auto IsPhaseHPLimitValid() -> std::optional<bool> { return CallForReturn<bool>(STR("IsPhaseHPLimitValid")); }
auto AddHP(FFixedPoint64_ PlusHP) -> bool
{
struct P { FFixedPoint64_ PlusHP; } p{ PlusHP };
return Call(STR("AddHP"), p);
}
auto FullRecoveryHP() -> bool { return CallVoid(STR("FullRecoveryHP")); }
auto IsHPFullRecovered() -> std::optional<bool> { return CallForReturn<bool>(STR("IsHPFullRecovered")); }
auto SetShieldHP(FFixedPoint64_ NextShieldHP) -> bool
{
struct P { FFixedPoint64_ NextSheildHP; } p{ NextShieldHP }; // engine spelling
return Call(STR("SetShieldHP"), p);
}
auto SetShieldMaxHP(FFixedPoint64_ NextShieldMaxHP) -> bool
{
struct P { FFixedPoint64_ NextSheildMaxHP; } p{ NextShieldMaxHP }; // engine spelling
return Call(STR("SetShieldMaxHP"), p);
}
auto DecreaseShieldHPByDamage(int32 Damage) -> bool
{
struct P { int32 Damage; } p{ Damage };
return Call(STR("DecreaseShieldHPByDamage"), p);
}
auto IsDead() -> std::optional<bool> { return CallForReturn<bool>(STR("IsDead")); }
auto GetPhysicalHealth() -> std::optional<EPalStatusPhysicalHealthType_>
{
return CallForReturn<EPalStatusPhysicalHealthType_>(STR("GetPhysicalHealth"));
}
auto SetPhysicalHealth(EPalStatusPhysicalHealthType_ PhysicalHealth) -> bool
{
struct P { EPalStatusPhysicalHealthType_ PhysicalHealth; } p{ PhysicalHealth };
return Call(STR("SetPhysicalHealth"), p);
}
auto IsRespawnReady() -> std::optional<bool> { return CallForReturn<bool>(STR("IsRespawnReady")); }
auto GetRespawnTime() -> std::optional<float> { return CallForReturn<float>(STR("GetRespawnTime")); }
// ---- combat stats -------------------------------------------------
auto GetMeleeAttack() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMeleeAttack")); }
auto GetMeleeAttack_withBuff() -> std::optional<int32> { return CallForReturn<int32>(STR("GetMeleeAttack_withBuff")); }
auto GetShotAttack() -> std::optional<int32> { return CallForReturn<int32>(STR("GetShotAttack")); }
auto GetShotAttack_withBuff() -> std::optional<int32> { return CallForReturn<int32>(STR("GetShotAttack_withBuff")); }
auto GetDefense() -> std::optional<int32> { return CallForReturn<int32>(STR("GetDefense")); }
auto GetDefense_withBuff() -> std::optional<int32> { return CallForReturn<int32>(STR("GetDefense_withBuff")); }
auto GetAttackRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetAttackRank")); }
auto GetDefenceRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetDefenceRank")); }
auto HasMasteredWaza(EPalWazaID_ WazaID) -> std::optional<bool>
{
struct P { EPalWazaID_ WazaID; bool ReturnValue; } p{ WazaID, false };
return CallForReturn(STR("HasMasteredWaza"), p, &P::ReturnValue);
}
auto AddEquipWaza(EPalWazaID_ WazaID) -> bool
{
struct P { EPalWazaID_ WazaID; } p{ WazaID };
return Call(STR("AddEquipWaza"), p);
}
auto RemoveEquipWaza(EPalWazaID_ WazaID) -> bool
{
struct P { EPalWazaID_ WazaID; } p{ WazaID };
return Call(STR("RemoveEquipWaza"), p);
}
auto ClearEquipWaza() -> bool { return CallVoid(STR("ClearEquipWaza")); }
// ---- sanity / hunger / stomach ------------------------------------
auto GetSanityValue() -> std::optional<float> { return CallForReturn<float>(STR("GetSanityValue")); }
auto GetMaxSanityValue() -> std::optional<float> { return CallForReturn<float>(STR("GetMaxSanityValue")); }
auto GetSanityRate() -> std::optional<float> { return CallForReturn<float>(STR("GetSanityRate")); }
auto GetAffectSanityValue() -> std::optional<float> { return CallForReturn<float>(STR("GetAffectSanityValue")); }
auto GetHungerType() -> std::optional<EPalStatusHungerType_>
{
return CallForReturn<EPalStatusHungerType_>(STR("GetHungerType"));
}
auto GetFullStomach() -> std::optional<float> { return CallForReturn<float>(STR("GetFullStomach")); }
auto GetMaxFullStomach() -> std::optional<float> { return CallForReturn<float>(STR("GetMaxFullStomach")); }
auto GetFullStomachRate() -> std::optional<float> { return CallForReturn<float>(STR("GetFullStomachRate")); }
auto GetFullStomachDecreasingRate() -> std::optional<float> { return CallForReturn<float>(STR("GetFullStomachDecreasingRate")); }
auto IsFullStomachDecreaseStoppedByFood() -> std::optional<bool>
{
return CallForReturn<bool>(STR("IsFullStomachDecreaseStoppedByFood"));
}
auto SetFullStomach(float NextValue) -> bool
{
struct P { float NextValue; } p{ NextValue };
return Call(STR("SetFullStomach"), p);
}
auto SetDecreaseFullStomachRates(FName Name, float Rate) -> bool
{
struct P { FName Name; float Rate; } p{ Name, Rate };
return Call(STR("SetDecreaseFullStomachRates"), p);
}
auto RemoveDecreaseFullStomachRates(FName Name) -> bool
{
struct P { FName Name; } p{ Name };
return Call(STR("RemoveDecreaseFullStomachRates"), p);
}
auto GetEffectFoodName() -> std::optional<FName> { return CallForReturn<FName>(STR("GetEffectFoodName")); }
auto GetEffectFoodName_FullStomachKeep() -> std::optional<FName> { return CallForReturn<FName>(STR("GetEffectFoodName_FullStomachKeep")); }
auto GetEffectFoodTimeRate() -> std::optional<float> { return CallForReturn<float>(STR("GetEffectFoodTimeRate")); }
auto GetEffectFoodTimeRate_FullStomachKeep() -> std::optional<float> { return CallForReturn<float>(STR("GetEffectFoodTimeRate_FullStomachKeep")); }
auto GetFoodStatusRate(EPalFoodStatusEffectType_ EffectType) -> std::optional<float>
{
struct P { EPalFoodStatusEffectType_ EffectType; float ReturnValue; } p{ EffectType, 0.f };
return CallForReturn(STR("GetFoodStatusRate"), p, &P::ReturnValue);
}
// ---- friendship -----------------------------------------------------
auto GetFriendshipRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetFriendshipRank")); }
auto GetFriendshipPoint() -> std::optional<int32> { return CallForReturn<int32>(STR("GetFriendshipPoint")); }
auto AddFriendShip(int32 Value, bool bApplyPassiveSkill) -> bool
{
struct P { int32 Value; bool bApplyPassiveSkill; } p{ Value, bApplyPassiveSkill };
return Call(STR("AddFriendShip"), p);
}
// ---- status points --------------------------------------------------
auto GetUnusedStatusPoint() -> std::optional<int32> { return CallForReturn<int32>(STR("GetUnusedStatusPoint")); }
auto DecrementUnusedStatusPoint() -> bool { return CallVoid(STR("DecrementUnusedStatusPoint")); }
auto IsStatusPointAllMax() -> std::optional<bool> { return CallForReturn<bool>(STR("IsStatusPointAllMax")); }
auto GetStatusPoint(FName StatusName) -> std::optional<int32>
{
struct P { FName StatusName; int32 ReturnValue; } p{ StatusName, 0 };
return CallForReturn(STR("GetStatusPoint"), p, &P::ReturnValue);
}
auto GetTotalStatusPoint(FName StatusName) -> std::optional<int32>
{
struct P { FName StatusName; int32 ReturnValue; } p{ StatusName, 0 };
return CallForReturn(STR("GetTotalStatusPoint"), p, &P::ReturnValue);
}
auto GetExStatusPoint(FName StatusName) -> std::optional<int32>
{
struct P { FName StatusName; int32 ReturnValue; } p{ StatusName, 0 };
return CallForReturn(STR("GetExStatusPoint"), p, &P::ReturnValue);
}
auto SetStatusPoint(FName StatusName, int32 Point) -> bool
{
struct P { FName StatusName; int32 Point; } p{ StatusName, Point };
return Call(STR("SetStatusPoint"), p);
}
auto SetExStatusPoint(FName StatusName, int32 Point) -> bool
{
struct P { FName StatusName; int32 Point; } p{ StatusName, Point };
return Call(STR("SetExStatusPoint"), p);
}
// Two outputs (bool return + int32& out), same non-CallForReturn
// shape as CheckValidWorkSuitability in PalDetailWidget.hpp.
auto IsStatusPointAddable(FName StatusName) -> std::optional<int32>
{
struct P { FName StatusName; int32 AddablePoint; bool ReturnValue; } p{ StatusName, 0, false };
if (!Call(STR("IsStatusPointAddable"), p) || !p.ReturnValue) return std::nullopt;
return p.AddablePoint;
}
// ---- work suitability -------------------------------------------------
auto GetCurrentWorkSuitability() -> std::optional<EPalWorkSuitability_>
{
return CallForReturn<EPalWorkSuitability_>(STR("GetCurrentWorkSuitability"));
}
auto GetWorkSpeedRank() -> std::optional<int32> { return CallForReturn<int32>(STR("GetWorkSpeedRank")); }
auto GetCraftSpeed() -> std::optional<int32> { return CallForReturn<int32>(STR("GetCraftSpeed")); }
auto GetCraftSpeed_withBuff() -> std::optional<int32> { return CallForReturn<int32>(STR("GetCraftSpeed_withBuff")); }
auto GetCraftSpeedSickRate() -> std::optional<float> { return CallForReturn<float>(STR("GetCraftSpeedSickRate")); }
auto GetBaseCampCraftSpeedBuffRate() -> std::optional<float> { return CallForReturn<float>(STR("GetBaseCampCraftSpeedBuffRate")); }
auto GetWorkerSick() -> std::optional<EPalBaseCampWorkerSickType_>
{
return CallForReturn<EPalBaseCampWorkerSickType_>(STR("GetWorkerSick"));
}
auto GetBaseCampWorkerEventType() -> std::optional<EPalBaseCampWorkerEventType_>
{
return CallForReturn<EPalBaseCampWorkerEventType_>(STR("GetBaseCampWorkerEventType"));
}
auto HasWorkSuitability(EPalWorkSuitability_ Suitability) -> std::optional<bool>
{
struct P { EPalWorkSuitability_ InWorkSuitability; bool ReturnValue; } p{ Suitability, false };
return CallForReturn(STR("HasWorkSuitability"), p, &P::ReturnValue);
}
auto HasWorkSuitabilityRank(EPalWorkSuitability_ Suitability, int32 Rank) -> std::optional<bool>
{
struct P { EPalWorkSuitability_ InWorkSuitability; int32 SuitabilityRank; bool ReturnValue; }
p{ Suitability, Rank, false };
return CallForReturn(STR("HasWorkSuitabilityRank"), p, &P::ReturnValue);
}
auto GetWorkSuitabilityRank(EPalWorkSuitability_ Suitability) -> std::optional<int32>
{
struct P { EPalWorkSuitability_ InWorkSuitability; int32 ReturnValue; } p{ Suitability, 0 };
return CallForReturn(STR("GetWorkSuitabilityRank"), p, &P::ReturnValue);
}
auto GetWorkSuitabilityRankWithCharacterRank(EPalWorkSuitability_ Suitability) -> std::optional<int32>
{
struct P { EPalWorkSuitability_ WorkSuitability; int32 ReturnValue; } p{ Suitability, 0 };
return CallForReturn(STR("GetWorkSuitabilityRankWithCharacterRank"), p, &P::ReturnValue);
}
auto GetRankBasedWorkSuitabilityBonus(EPalWorkSuitability_ Suitability) -> std::optional<int32>
{
struct P { EPalWorkSuitability_ WorkSuitability; int32 ReturnValue; } p{ Suitability, 0 };
return CallForReturn(STR("GetRankBasedWorkSuitabilityBonus"), p, &P::ReturnValue);
}
auto GetCraftSpeedByWorkSuitability(EPalWorkSuitability_ Suitability) -> std::optional<int32>
{
struct P { EPalWorkSuitability_ WorkSuitability; int32 ReturnValue; } p{ Suitability, 0 };
return CallForReturn(STR("GetCraftSpeedByWorkSuitability"), p, &P::ReturnValue);
}
auto GetCraftSpeedBuffRate(EPalWorkSuitability_ Suitability) -> std::optional<float>
{
struct P { EPalWorkSuitability_ WorkSuitability; float ReturnValue; } p{ Suitability, 0.f };
return CallForReturn(STR("GetCraftSpeedBuffRate"), p, &P::ReturnValue);
}
auto GetCraftSpeed_withBuff_WorkSuitability(EPalWorkSuitability_ Suitability) -> std::optional<int32>
{
struct P { EPalWorkSuitability_ Suitability; int32 ReturnValue; } p{ Suitability, 0 };
return CallForReturn(STR("GetCraftSpeed_withBuff_WorkSuitability"), p, &P::ReturnValue);
}
auto SetWorkSuitabilityAddRank(EPalWorkSuitability_ Suitability, int32 AddRank) -> bool
{
struct P { EPalWorkSuitability_ WorkSuitability; int32 addRank; } p{ Suitability, AddRank };
return Call(STR("SetWorkSuitabilityAddRank"), p);
}
// ---- passive skills ---------------------------------------------------
//
// GetPassiveSkillList (TArray<FName>) is NOT wrapped -- see class
// comment. Add/Remove take scalar FName params, no such problem.
auto AddPassiveSkill(FName AddSkill, FName OverrideSkill) -> bool
{
struct P { FName AddSkill; FName OverrideSkill; } p{ AddSkill, OverrideSkill };
return Call(STR("AddPassiveSkill"), p);
}
auto RemovePassiveSkill(FName SkillId) -> bool
{
struct P { FName SkillId; } p{ SkillId };
return Call(STR("RemovePassiveSkill"), p);
}
auto GetPassiveRateBySkillEffect(EPalPassiveSkillEffectType_ EffectType) -> std::optional<float>
{
struct P { EPalPassiveSkillEffectType_ EffectType; float ReturnValue; } p{ EffectType, 0.f };
return CallForReturn(STR("GetPassiveRateBySkillEffect"), p, &P::ReturnValue);
}
auto GetPassiveRateByEquipment(EPalPassiveSkillEffectType_ EffectType) -> std::optional<float>
{
struct P { EPalPassiveSkillEffectType_ EffectType; float ReturnValue; } p{ EffectType, 0.f };
return CallForReturn(STR("GetPassiveRateByEquipment"), p, &P::ReturnValue);
}
// ---- classification / misc flags ---------------------------------------
auto GetSizeType() -> std::optional<EPalSizeType_> { return CallForReturn<EPalSizeType_>(STR("GetSizeType")); }
auto GetGroupType() -> std::optional<EPalGroupType_> { return CallForReturn<EPalGroupType_>(STR("GetGroupType")); }
auto GetGroupId() -> std::optional<FGuid_> { return CallForReturn<FGuid_>(STR("GetGroupId")); }
auto GetBaseCampId() -> std::optional<FGuid_> { return CallForReturn<FGuid_>(STR("GetBaseCampId")); }
auto GetArenaRank() -> std::optional<EPalArenaRank_> { return CallForReturn<EPalArenaRank_>(STR("GetArenaRank")); }
auto GetArenaRankPoint() -> std::optional<int32> { return CallForReturn<int32>(STR("GetArenaRankPoint")); }
auto IsInArena() -> std::optional<bool> { return CallForReturn<bool>(STR("IsInArena")); }
auto IsInRaidArea() -> std::optional<bool> { return CallForReturn<bool>(STR("IsInRaidArea")); }
auto IsUncapturable() -> std::optional<bool> { return CallForReturn<bool>(STR("IsUncapturable")); }
auto IsForceCapturable() -> std::optional<bool> { return CallForReturn<bool>(STR("IsForceCapturable")); }
auto IsAwakening() -> std::optional<bool> { return CallForReturn<bool>(STR("IsAwakening")); }
auto IsPartBroken() -> std::optional<bool> { return CallForReturn<bool>(STR("IsPartBroken")); }
auto IsParts() -> std::optional<bool> { return CallForReturn<bool>(STR("IsParts")); }
auto GetParentParameterObject() -> UObject*
{
struct P { UObject* ReturnValue; } p{ nullptr };
auto Result = CallForReturn(STR("GetParentParameter"), p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
auto IsAssignedToExpedition() -> std::optional<bool> { return CallForReturn<bool>(STR("IsAssignedToExpedition")); }
auto IsAssignedToExpeditionIn(FGuid_ MapObjectId) -> std::optional<bool>
{
struct P { FGuid_ MapObjectConcreteInstanceId; bool ReturnValue; } p{ MapObjectId, false };
return CallForReturn(STR("IsAssignedToExpeditionIn"), p, &P::ReturnValue);
}
auto IsExcludedFromTeamMission() -> std::optional<bool> { return CallForReturn<bool>(STR("IsExcludedFromTeamMission")); }
auto CanTargetFromAI() -> std::optional<bool> { return CallForReturn<bool>(STR("CanTargetFromAI")); }
auto HasGenusCategory(EPalGenusCategoryType_ Category) -> std::optional<bool>
{
struct P { EPalGenusCategoryType_ Category; bool ReturnValue; } p{ Category, false };
return CallForReturn(STR("HasGenusCategory"), p, &P::ReturnValue);
}
auto CanAddTalentByItem(FName ItemName) -> std::optional<bool>
{
struct P { FName ItemName; bool ReturnValue; } p{ ItemName, false };
return CallForReturn(STR("CanAddTalentByItem"), p, &P::ReturnValue);
}
auto GetNPCWeaponType() -> std::optional<EPalWeaponType_> { return CallForReturn<EPalWeaponType_>(STR("GetNPCWeaponType")); }
auto GetEquipItemContainerId() -> std::optional<FPalContainerId_>
{
return CallForReturn<FPalContainerId_>(STR("GetEquipItemContainerId"));
}
auto SetUncapturable(bool bInUncapturable) -> bool
{
struct P { bool bInUncapturable; } p{ bInUncapturable };
return Call(STR("SetUncapturable"), p);
}
auto SetForceCapturable(bool bInForceCapturable) -> bool
{
struct P { bool bInForceCapturable; } p{ bInForceCapturable };
return Call(STR("SetForceCapturable"), p);
}
auto SetInArena(bool InArena) -> bool
{
struct P { bool InArena; } p{ InArena };
return Call(STR("SetInArena"), p);
}
auto SetInRaidArea(bool InRaidArea) -> bool
{
struct P { bool InRaidArea; } p{ InRaidArea };
return Call(STR("SetInRaidArea"), p);
}
auto SetCanTargetFromAI(bool bInCanTargetFromAI) -> bool
{
struct P { bool bInCanTargetFromAI; } p{ bInCanTargetFromAI };
return Call(STR("SetCanTargetFromAI"), p);
}
auto SetSkinName(FName InSkinName) -> bool
{
struct P { FName InSkinName; } p{ InSkinName };
return Call(STR("SetSkinName"), p);
}
auto SetSkinAppliedCharacterId(FGuid_ InCharacterId) -> bool
{
struct P { FGuid_ InCharacterId; } p{ InCharacterId };
return Call(STR("SetSkinAppliedCharacterId"), p);
}
auto SetSecurityPoliceTargetPlayerId(FGuid_ PlayerId) -> bool
{
struct P { FGuid_ PlayerId; } p{ PlayerId };
return Call(STR("SetSecurityPoliceTargetPlayerId"), p);
}
auto SetInvaderData(EPalInvaderType_ InvaderType, FGuid_ InBaseCampId) -> bool
{
struct P { EPalInvaderType_ InvaderType; FGuid_ InBaseCampId; } p{ InvaderType, InBaseCampId };
return Call(STR("SetInvaderData"), p);
}
auto SetDisableNaturalUpdate(FName Key, bool Disable) -> bool
{
struct P { FName Key; bool Disable; } p{ Key, Disable };
return Call(STR("SetDisableNaturalUpdate"), p);
}
auto SetDisableNaturalHealing(FName Key, bool Disable) -> bool
{
struct P { FName Key; bool Disable; } p{ Key, Disable };
return Call(STR("SetDisableNaturalHealing"), p);
}
auto NaturalUpdateSaveParameter(EPalCharacterNaturalUpdateType_ Type) -> bool
{
struct P { EPalCharacterNaturalUpdateType_ Type; } p{ Type };
return Call(STR("NaturalUpdateSaveParameter"), p);
}
auto SetForcePartBreak() -> bool { return CallVoid(STR("SetForcePartBreak")); }
// ---- medical bed / misc actions -----------------------------------
auto StartRecuperatingInMedicalBed() -> bool { return CallVoid(STR("StartRecuperatingInMedicalBed")); }
auto RecuperateInMedicalBed() -> bool { return CallVoid(STR("RecuperateInMedicalBed")); }
auto EndRecuperatingInMedicalBed() -> bool { return CallVoid(STR("EndRecuperatingInMedicalBed")); }
auto StartRemainderOfLifeTimer() -> bool { return CallVoid(STR("StartRemainderOfLifeTimer")); }
};
}

110
Api/Pal/PalTypes.hpp Normal file
View File

@@ -0,0 +1,110 @@
#pragma once
#include <cstdint>
namespace PalUIExtension::Api::Pal
{
struct FGuid_ { uint32_t A{}, B{}, C{}, D{}; };
struct FFixedPoint64_ { int64_t Value{}; };
struct FPalContainerId_ { FGuid_ ID{}; };
using EPalTribeID_ = uint16_t;
using EPalWazaID_ = uint16_t;
using EPalPassiveSkillEffectType_ = uint8_t;
enum class EPalStatusPhysicalHealthType_ : uint8_t
{
Healthful = 0, MinorInjury = 1, Severe = 2,
Dying = 3, DeadBody = 4, CloudCemetery = 5,
};
enum class EPalGroupType_ : uint8_t
{
Undefined = 0, Neutral = 1, Organization = 2, IndependentGuild = 3,
Guild = 4, ResidentEnemy = 5, RaidBoss = 6,
};
enum class EPalArenaRank_ : uint8_t
{
Bronze = 0, Silver = 1, Gold = 2, Platinum = 3,
Diamond = 4, Master = 5, Legend = 6,
};
enum class EPalGenusCategoryType_ : uint8_t
{
None = 0, Humanoid = 1, FourLegged = 2, Dragon = 3,
Fish = 4, Bird = 5, Monster = 6, Other = 7,
};
enum class EPalExpCalcType_ : uint8_t { None = 0, Build = 1, Craft = 2 };
enum class EPalSizeType_ : uint8_t
{
None = 0, XS = 1, S = 2, M = 3, L = 4, XL = 5,
};
enum class EPalStatusHungerType_ : uint8_t
{
Default = 0, Hunger = 1, Starvation = 2,
};
enum class EPalWeaponType_ : uint8_t
{
None = 0, ThrowObject = 1, Handgun = 2, AssaultRifle = 3, Shotgun = 4,
SniperRifle = 5, RocketLauncher = 6, MeleeWeapon = 7, Bow = 8,
BowGun = 9, FlameThrower = 10, GatlingGun = 11, Liftup = 12,
LaserRifle = 13, MissileLauncher = 14, GrenadeLauncher = 15,
Katana = 16, MetalDetector = 17, GiantClub = 18, FishingRod = 19,
LaserMiningTool = 20, MAX = 21,
};
enum class EPalBaseCampWorkerEventType_ : uint8_t
{
None = 0, Escape = 1, OverworkDeath = 2, Sick = 3, DodgeWork = 4,
DodgeWork_Short = 5, DodgeWork_Sleep = 6, EatTooMuch = 7,
Trantrum = 8, FightWithFriend = 9, TurnFoodBox = 10, DestroyBuilding = 11,
};
enum class EPalBaseCampWorkerSickType_ : uint8_t
{
None = 0, Cold = 1, Sprain = 2, Bulimia = 3, GastricUlcer = 4,
Fracture = 5, Weakness = 6, DepressionSprain = 7, DisturbingElement = 8,
};
enum class EPalInvaderType_ : uint8_t { None = 0, InvaderEnemy = 1, VisitorNPC = 2 };
enum class EPalFoodStatusEffectType_ : uint8_t
{
None = 0, Attack = 1, Defense = 2, HungerResist = 3, SANResist = 4,
WorkSpeed = 5, Regene_Hp = 6, MaxSP = 7, Exp_Increase = 8,
LeanBackInvalid = 9, KnockbackInvalid = 10, ExplosionResist = 11,
LeanBackAndKnockbackInvalid = 12, FullStomachKeep = 13,
};
enum class EPalCharacterNaturalUpdateType_ : uint8_t
{
Player = 0, OtomoPal = 1, BaseCampPal = 2,
};
enum class EPalOrganizationType_ : uint8_t
{
None = 0, Guild = 1, Police = 2, City = 3, Brigade = 4,
TeamBlackHunter = 5, TeamFireCult = 6, TeamWelfareGroup = 7,
Ally = 8, MAX = 9,
};
enum class EPalBattleBGMType_ : uint8_t
{
None = 0, Cute = 1, Cool = 2, Strong = 3, Human_Common = 4,
Human_Villain = 5, FieldBoss_Tier_1 = 6, FieldBoss_Tier_2 = 7,
FieldBoss_Tier_3 = 8, FieldBoss_Tier_4 = 9, FieldBoss_Tier_5 = 10,
Predator = 11, EyeofCthulhu = 12, WildlifeSanctuaryDrone = 13,
Machine = 14, Legend = 15, KingWhale = 16, RaidBoss = 17,
TowerBoss = 18, RaidBoss_KingBahamut = 19, RaidBoss_DarkMechaDragon = 20,
RaidBoss_MoonLord = 21, RaidBoss_LegendDeer = 22, RaidBoss_LegendDeer2 = 23,
WorldTreeDragon = 24,
};
}

View File

@@ -0,0 +1,155 @@
#pragma once
#include <optional>
#include <Unreal/FText.hpp>
#include <Unreal/NameTypes.hpp>
#include <Api/UnrealWrapper.hpp>
#include "PalIndividual.hpp" // EPalElementType_
namespace PalUIExtension::Api::Pal
{
class PalUIStatusModel : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalUIStatusModel"); }
static auto DebugTag() -> const TCHAR* { return STR("PalUIStatusModel"); }
PalUIStatusModel() = default;
explicit PalUIStatusModel(UObject* Obj) : UnrealWrapper(Obj, ClassOf<PalUIStatusModel>(), DebugTag()) {}
// Count of pals currently loaded into the model -- "pal number".
auto GetDisplayPalNum() -> std::optional<uint8>
{
return CallForReturn<uint8>(STR("GetDisplayPalNum"));
}
auto GetDisplayPalHandle(uint8 Index) -> UObject*
{
struct P { uint8 Index; UObject* ReturnValue; } p{ Index, nullptr };
auto Result = CallForReturn(STR("GetDisplayPalHandle"), p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
auto GetNowSelectedIndex() -> std::optional<uint8>
{
return CallForReturn<uint8>(STR("GetNowSelectedIndex"));
}
auto ChangeIndex(uint8 Index) -> bool
{
struct P { uint8 Index; } p{ Index };
return Call(STR("ChangeIndex"), p);
}
auto OnClickedPalIcon(int32 Index) -> bool
{
struct P { int32 Index; } p{ Index };
return Call(STR("OnClickedPalIcon"), p);
}
// ---- extended: mechanical Index -> stat getters ----------------
auto GetDisplayLevel(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayLevel"), p, &P::ReturnValue);
}
auto GetDisplaySpeed(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplaySpeed"), p, &P::ReturnValue);
}
auto GetDisplayMeleeAttack(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayMeleeAttack"), p, &P::ReturnValue);
}
auto GetDisplayShotAttack(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayShotAttack"), p, &P::ReturnValue);
}
auto GetDisplayDefence(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayDefence"), p, &P::ReturnValue);
}
auto GetDisplayEatingHabits(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayEatingHabits"), p, &P::ReturnValue);
}
auto GetDisplayNowExp(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayNowExp"), p, &P::ReturnValue);
}
auto GetDisplayNextExp(int32 Index) -> std::optional<int32>
{
struct P { int32 Index; int32 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayNextExp"), p, &P::ReturnValue);
}
auto GetDisplayHunger(int32 Index) -> std::optional<float>
{
struct P { int32 Index; float ReturnValue; } p{ Index, 0.f };
return CallForReturn(STR("GetDisplayHunger"), p, &P::ReturnValue);
}
auto GetDisplayMaxHunger(int32 Index) -> std::optional<float>
{
struct P { int32 Index; float ReturnValue; } p{ Index, 0.f };
return CallForReturn(STR("GetDisplayMaxHunger"), p, &P::ReturnValue);
}
auto GetDisplayElementType1(int32 Index) -> std::optional<EPalElementType_>
{
struct P { int32 Index; EPalElementType_ ReturnValue; } p{ Index, EPalElementType_::None };
return CallForReturn(STR("GetDisplayElementType1"), p, &P::ReturnValue);
}
auto GetDisplayElementType2(int32 Index) -> std::optional<EPalElementType_>
{
struct P { int32 Index; EPalElementType_ ReturnValue; } p{ Index, EPalElementType_::None };
return CallForReturn(STR("GetDisplayElementType2"), p, &P::ReturnValue);
}
// Raw byte -- see class comment. Do not assume ordering/meaning.
auto GetDisplayPhysicalHealthTypeRaw(int32 Index) -> std::optional<uint8>
{
struct P { int32 Index; uint8 ReturnValue; } p{ Index, 0 };
return CallForReturn(STR("GetDisplayPhysicalHealthType"), p, &P::ReturnValue);
}
// ---- extended: FText / FString getters -------------------------
auto GetDisplayDefaultName(int32 Index) -> std::optional<FText>
{
struct P { int32 Index; FText ReturnValue; } p{ Index, {} };
return CallForReturn(STR("GetDisplayDefaultName"), p, &P::ReturnValue);
}
auto GetDisplayCoopActionName(int32 Index) -> std::optional<FText>
{
struct P { int32 Index; FText ReturnValue; } p{ Index, {} };
return CallForReturn(STR("GetDisplayCoopActionName"), p, &P::ReturnValue);
}
auto GetDisplayActiveSkillName(int32 Index, int32 SkillIndex) -> std::optional<FText>
{
struct P { int32 Index; int32 SkillIndex; FText ReturnValue; } p{ Index, SkillIndex, {} };
return CallForReturn(STR("GetDisplayActiveSkillName"), p, &P::ReturnValue);
}
auto GetDisplayNickName(int32 Index) -> std::optional<FString>
{
struct P { int32 Index; FString OutName; } p{ Index, {} };
if (!Call(STR("GetDisplayNickName"), p)) return std::nullopt;
return p.OutName;
}
auto ChangeNickname(int32 Index, const TCHAR* NewNickName) -> bool
{
struct P { int32 Index; FString NewNickName; } p{ Index, FString(NewNickName) };
return Call(STR("ChangeNickname"), p);
}
};
}

123
Api/Pal/PalUtility.hpp Normal file
View File

@@ -0,0 +1,123 @@
#pragma once
#include <cstdint>
#include <optional>
#include <unordered_map>
#include <Reflection/UnrealObjectRef.hpp>
#include <Api/UnrealWrapper.hpp>
#include "PalDatabaseCharacterParameter.hpp"
namespace PalUIExtension::Api::Pal
{
class PalUtility : public UnrealWrapper
{
public:
static auto ClassPath() -> const TCHAR* { return STR("/Script/Pal.PalUtility"); }
static auto CDOPath() -> const TCHAR* { return STR("/Script/Pal.Default__PalUtility"); }
static auto DebugTag() -> const TCHAR* { return STR("PalUtility"); }
static auto Instance() -> PalUtility&
{
static PalUtility Singleton{};
return Singleton;
}
// ---- static getters -----------------------------------------
//
// Add more here as you need them -- see the class comment for
// the one-line shape.
auto GetDatabaseCharacterParameter(UObject* WorldContextObject) -> PalDatabaseCharacterParameter
{
return GetSingleton<PalDatabaseCharacterParameter>(
STR("GetDatabaseCharacterParameter"), WorldContextObject);
}
auto ZukanIndexFor(FName CharacterId, UObject* WorldContextObject) -> std::optional<int32>
{
const uint64_t Key = NameKey(CharacterId);
if (auto It = s_zukan_cache.find(Key); It != s_zukan_cache.end())
{
if (It->second == kNoZukanEntry) return std::nullopt;
return It->second;
}
PalDatabaseCharacterParameter DB = GetDatabaseCharacterParameter(WorldContextObject);
if (!DB)
{
return std::nullopt;
}
auto Index = DB.GetZukanIndexResolved(CharacterId);
s_zukan_cache.emplace(Key, Index.value_or(kNoZukanEntry));
return Index;
}
static auto ClearZukanCache() -> void { s_zukan_cache.clear(); }
auto NocturnalFor(FName CharacterId, UObject* WorldContextObject) -> std::optional<bool>
{
const uint64_t Key = NameKey(CharacterId);
if (auto It = s_nocturnal_cache.find(Key); It != s_nocturnal_cache.end())
{
return It->second != 0;
}
PalDatabaseCharacterParameter DB = GetDatabaseCharacterParameter(WorldContextObject);
if (!DB) return std::nullopt;
const FName RowName = PalDatabaseCharacterParameter::ResolveBaseRowName(CharacterId);
auto Nocturnal = DB.GetNocturnal(RowName);
if (!Nocturnal.has_value()) return std::nullopt;
s_nocturnal_cache.emplace(Key, *Nocturnal ? uint8_t{ 1 } : uint8_t{ 0 });
return Nocturnal;
}
static auto ClearNocturnalCache() -> void { s_nocturnal_cache.clear(); }
private:
PalUtility() : UnrealWrapper(ResolveCDO(), ClassOf<PalUtility>(), DebugTag()) {}
static constexpr int32 kNoZukanEntry = -1;
static inline std::unordered_map<uint64_t, int32> s_zukan_cache{};
static inline std::unordered_map<uint64_t, uint8_t> s_nocturnal_cache{};
static auto NameKey(FName N) -> uint64_t
{
return (static_cast<uint64_t>(N.GetComparisonIndex().ToUnstableInt()) << 32)
| static_cast<uint64_t>(static_cast<uint32_t>(N.GetNumber()));
}
PalUtility(const PalUtility&) = delete;
auto operator=(const PalUtility&) -> PalUtility & = delete;
static auto ResolveCDO() -> UObject*
{
static Reflection::UnrealObjectRef Ref{ CDOPath(), DebugTag() };
return Ref.Get();
}
auto CallStaticObjectGetter(const TCHAR* FunctionName, UObject* WorldContextObject) -> UObject*
{
struct P { UObject* WorldContextObject; UObject* ReturnValue; } p{ WorldContextObject, nullptr };
auto Result = CallForReturn(FunctionName, p, &P::ReturnValue);
return (Result && *Result) ? *Result : nullptr;
}
template <typename T>
auto GetSingleton(const TCHAR* FunctionName, UObject* WorldContextObject) -> T
{
UObject* Obj = CallStaticObjectGetter(FunctionName, WorldContextObject);
return Obj ? T{ Obj } : T{};
}
};
}