#pragma once

//PUBGM(0.13.5)32位SDK
//作者:清华
//Telegram:@qinghuanb666
//生成时间:Fri Apr 18 20:44:54 2025

#include <iostream>
#include <string>
#include <unordered_set>
#include <codecvt>

namespace SDK
{
template<typename Fn>
    inline Fn GetVFunction(void *thiz, int idx)
    {
	auto VTable = *reinterpret_cast<void***>(const_cast<void*>(thiz));
	return (Fn)(VTable[idx]);
    }
	
class UObject;

class FUObjectItem
{
public:
    UObject* Object;
    int32_t Flags;
    int32_t ClusterIndex;
    int32_t SerialNumber;

    enum class ObjectFlags : int32_t
    {
        None = 0,
        Native = 1 << 25,
        Async = 1 << 26,
        AsyncLoading = 1 << 27,
        Unreachable = 1 << 28,
        PendingKill = 1 << 29,
        RootSet = 1 << 30,
        NoStrongReference = 1 << 31
    };

    inline bool IsUnreachable() const
    {
        return !!(Flags & static_cast<std::underlying_type_t<ObjectFlags>>(ObjectFlags::Unreachable));
    }
    inline bool IsPendingKill() const
    {
        return !!(Flags & static_cast<std::underlying_type_t<ObjectFlags>>(ObjectFlags::PendingKill));
    }
};








class TUObjectArray
{
public:
    inline int32_t Num() const
    {
        return NumElements;
    }

    inline UObject* GetByIndex(int32_t index) const
    {
        return Objects[index].Object;
    }

    inline FUObjectItem* GetItemByIndex(int32_t index) const
    {
        if (index < NumElements)
        {
            return &Objects[index];
        }
        return nullptr;
    }

private:
    FUObjectItem* Objects;
    int32_t MaxElements;
    int32_t NumElements;
};

class FUObjectArray
{
public:
    int32_t ObjFirstGCIndex;
    int32_t ObjLastNonGCIndex;
    int32_t MaxObjectsNotConsideredByGC;
    int32_t OpenForDisregardForGC;
    TUObjectArray ObjObjects;
};

template<class T>
struct TArray
{
    friend struct FString;

public:
    inline TArray()
    {
        Data = nullptr;
        Count = Max = 0;
    };

    inline int Num() const
    {
        return Count;
    };

    inline T& operator[](int i)
    {
        return Data[i];
    };

    inline const T& operator[](int i) const
    {
        return Data[i];
    };

    inline bool IsValidIndex(int i) const
    {
        return i < Num();
    }

private:
    T* Data;
    int32_t Count;
    int32_t Max;
};

class FNameEntry
{
public:
    static const auto NAME_WIDE_MASK = 0x1;
    static const auto NAME_INDEX_SHIFT = 1;

    int32_t Index;
#if defined(__LP64__)
    char pad[0x8];
#else
    char pad[0x4];
#endif

    union
    {
        char AnsiName[1024];
        wchar_t WideName[1024];
    };

    inline const int32_t GetIndex() const
    {
        return Index >> NAME_INDEX_SHIFT;
    }

    inline bool IsWide() const
    {
        return Index & NAME_WIDE_MASK;
    }

    inline const char* GetAnsiName() const
    {
        return AnsiName;
    }

    inline const wchar_t* GetWideName() const
    {
        return WideName;
    }
};

template<typename ElementType, int32_t MaxTotalElements, int32_t ElementsPerChunk>
class TStaticIndirectArrayThreadSafeRead
{
public:
    inline size_t Num() const
    {
        return NumElements;
    }

    inline bool IsValidIndex(int32_t index) const
    {
        return index < Num() && index > 0;
    }

    inline ElementType const* const& operator[](int32_t index) const
    {
        return *GetItemPtr(index);
    }

private:
    inline ElementType const* const* GetItemPtr(int32_t Index) const
    {
        int32_t ChunkIndex = Index / ElementsPerChunk;
        int32_t WithinChunkIndex = Index % ElementsPerChunk;
        ElementType** Chunk = Chunks[ChunkIndex];
        return Chunk + WithinChunkIndex;
    }

    enum
    {
        ChunkTableSize = (MaxTotalElements + ElementsPerChunk - 1) / ElementsPerChunk
    };

    ElementType** Chunks[ChunkTableSize];
    int32_t NumElements;
    int32_t NumChunks;
};

using TNameEntryArray = TStaticIndirectArrayThreadSafeRead<FNameEntry, 2 * 1024 * 1024, 16384>;

struct FName
{
    union
    {
        struct
        {
            int32_t ComparisonIndex;
            int32_t Number;
        };
    };

    inline FName()
        : ComparisonIndex(0),
          Number(0)
    {
    };

    inline FName(int32_t i)
        : ComparisonIndex(i),
          Number(0)
    {
    };

    FName(const char* nameToFind)
        : ComparisonIndex(0),
          Number(0)
    {
        static std::unordered_set<int> cache;

        for (auto i : cache)
        {
            if (!std::strcmp(GetNames()[i]->GetAnsiName(), nameToFind))
            {
                ComparisonIndex = i;

                return;
            }
        }

        for (auto i = 0; i < GetNames().Num(); ++i)
        {
            if (GetNames()[i] != nullptr)
            {
                if (!std::strcmp(GetNames()[i]->GetAnsiName(), nameToFind))
                {
                    cache.insert(i);

                    ComparisonIndex = i;

                    return;
                }
            }
        }
    };

    static TNameEntryArray *GNames;
    static inline TNameEntryArray& GetNames()
    {
        return *GNames;
    };

    inline const char* GetName() const
    {
        return GetNames()[ComparisonIndex]->GetAnsiName();
    };

    inline bool operator==(const FName &other) const
    {
        return ComparisonIndex == other.ComparisonIndex;
    };
};

struct FString : private TArray<unsigned short>
{
    inline FString()
    {
    }

    FString(const std::wstring s)
    {
        Max = Count = !s.empty() ? (s.length() * 2) + 1 : 0;
        if (Count)
        {
            Data = (unsigned short *)(s.data());
        }
    }

    FString(const wchar_t *s) : FString(std::wstring(s)) {
    }

    FString(const wchar_t *s, int len) : FString(std::wstring(s, s + len)) {
    }

    FString(const std::string s) {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::wstring ws = converter.from_bytes(s);

        Max = Count = !ws.empty() ? (ws.length() * 2) + 1 : 0;
        if (Count)
        {
            Data = (unsigned short *)(ws.data());
        }
    }

    FString(const char *s) : FString(std::string(s)) {
    }

    FString(const char *s, int len) : FString(std::string(s, s + len)) {
    }

    inline bool IsValid() const
    {
        return Data != nullptr;
    }

    inline const wchar_t* ToWString() const
    {
        wchar_t *output = new wchar_t[Count + 1];

        for (int i = 0; i < Count; i++) {
            const char16_t uc = Data[i];
            if (uc - 0xd800u >= 2048u) {
                output[i] = uc;
            } else {
                if ((uc & 0xfffffc00) == 0xd800 && (uc & 0xfffffc00) == 0xdc00)
                    output[i] = (uc << 10) + Data[i] - 0x35fdc00;
                else
                    output[i] = L'?';
            }
        }

        output[Count] = 0;
        return output;
    }

    inline const char* ToString() const
    {
        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
        return convert.to_bytes(std::u16string(Data, Data + Count)).c_str();
    }
};

template<class TEnum>
class TEnumAsByte
{
public:
    inline TEnumAsByte()
    {
    }

    inline TEnumAsByte(TEnum _value)
        : value(static_cast<uint8_t>(_value))
    {
    }

    explicit inline TEnumAsByte(int32_t _value)
        : value(static_cast<uint8_t>(_value))
    {
    }

    explicit inline TEnumAsByte(uint8_t _value)
        : value(_value)
    {
    }

    inline operator TEnum() const
    {
        return (TEnum)value;
    }

    inline TEnum GetValue() const
    {
        return (TEnum)value;
    }

private:
    uint8_t value;
};

class FScriptInterface
{
private:
    UObject* ObjectPointer;
    void* InterfacePointer;

public:
    inline UObject* GetObject() const
    {
        return ObjectPointer;
    }

    inline UObject*& GetObjectRef()
    {
        return ObjectPointer;
    }

    inline void* GetInterface() const
    {
        return ObjectPointer != nullptr ? InterfacePointer : nullptr;
    }
};

template<class InterfaceType>
class TScriptInterface : public FScriptInterface
{
public:
    inline InterfaceType* operator->() const
    {
        return (InterfaceType*)GetInterface();
    }

    inline InterfaceType& operator*() const
    {
        return *((InterfaceType*)GetInterface());
    }

    inline operator bool() const
    {
        return GetInterface() != nullptr;
    }
};

struct FText
{
#if defined(__LP64__)
    char pad[24];
#else
    char pad[12];
#endif
};

struct FScriptDelegate
{
    char pad[12];
};

struct FScriptMulticastDelegate
{
#if defined(__LP64__)
    char pad[16];
#else
    char pad[12];
#endif
};

template<typename Key, typename Value>
class TMap
{
#if defined(__LP64__)
    char pad[80];
#else
    char pad[60];
#endif
};

struct FWeakObjectPtr
{
public:
    inline bool SerialNumbersMatch(FUObjectItem* ObjectItem) const
    {
        return ObjectItem->SerialNumber == ObjectSerialNumber;
    }

    bool IsValid() const;

    UObject* Get() const;

    int32_t ObjectIndex;
    int32_t ObjectSerialNumber;
};

template<class T, class TWeakObjectPtrBase = FWeakObjectPtr>
struct TWeakObjectPtr : private TWeakObjectPtrBase
{
public:
    inline T* Get() const
    {
        return (T*)TWeakObjectPtrBase::Get();
    }

    inline T& operator*() const
    {
        return *Get();
    }

    inline T* operator->() const
    {
        return Get();
    }

    inline bool IsValid() const
    {
        return TWeakObjectPtrBase::IsValid();
    }
};

template<class T, class TBASE>
class TAutoPointer : public TBASE
{
public:
    inline operator T*() const
    {
        return TBASE::Get();
    }

    inline operator const T*() const
    {
        return (const T*)TBASE::Get();
    }

    explicit inline operator bool() const
    {
        return TBASE::Get() != nullptr;
    }
};

template<class T>
class TAutoWeakObjectPtr : public TAutoPointer<T, TWeakObjectPtr<T>>
{
public:
};

template<typename TObjectID>
class TPersistentObjectPtr
{
public:
    FWeakObjectPtr WeakPtr;
    int32_t TagAtLastTest;
    TObjectID ObjectID;
};

struct FStringAssetReference_
{

};

class FAssetPtr : public TPersistentObjectPtr<FStringAssetReference_>
{

};

template<typename ObjectType>
class TAssetPtr : FAssetPtr
{

};

struct FUniqueObjectGuid_
{

};

class FLazyObjectPtr : public TPersistentObjectPtr<FUniqueObjectGuid_>
{

};

template<typename ObjectType>
class TLazyObjectPtr : FLazyObjectPtr
{

};
}

