From 5154632619cee025456c90009d508b309771683d Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sun, 13 Aug 2023 15:24:29 +0300 Subject: [PATCH] Wrapper for the discord user type. --- module/Library/Discord.cpp | 2 + module/Library/Discord/Misc.hpp | 1 - module/Library/Discord/User.cpp | 133 +++++++ module/Library/Discord/User.hpp | 536 +++++++++++++++++++++++++++ module/Library/Discord/Utilities.hpp | 53 +++ 5 files changed, 724 insertions(+), 1 deletion(-) diff --git a/module/Library/Discord.cpp b/module/Library/Discord.cpp index e004badd..8546d65d 100644 --- a/module/Library/Discord.cpp +++ b/module/Library/Discord.cpp @@ -29,6 +29,7 @@ void ProcessDiscord() extern void Register_Discord_Constants(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Events(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Misc(HSQUIRRELVM vm, Table & ns); +extern void Register_Discord_User(HSQUIRRELVM vm, Table & ns); extern void Register_Discord_Cluster(HSQUIRRELVM vm, Table & ns); // ================================================================================================ @@ -43,6 +44,7 @@ void Register_Discord(HSQUIRRELVM vm) ns.Bind(_SC("Event"), ens); } Register_Discord_Misc(vm, ns); + Register_Discord_User(vm, ns); Register_Discord_Cluster(vm, ns); // -------------------------------------------------------------------------------------------- RootTable(vm).Bind(_SC("SqDiscord"), ns); diff --git a/module/Library/Discord/Misc.hpp b/module/Library/Discord/Misc.hpp index c04d4664..4b14af02 100644 --- a/module/Library/Discord/Misc.hpp +++ b/module/Library/Discord/Misc.hpp @@ -215,7 +215,6 @@ struct DpVoiceState SQMOD_NODISCARD bool IsSuppressed() const { return Valid().is_suppressed(); } }; - /* ------------------------------------------------------------------------------------------------ * Represents the voice state of a user on a guild. */ diff --git a/module/Library/Discord/User.cpp b/module/Library/Discord/User.cpp index 7c3e19b4..f8b56a4b 100644 --- a/module/Library/Discord/User.cpp +++ b/module/Library/Discord/User.cpp @@ -4,6 +4,139 @@ // ------------------------------------------------------------------------------------------------ namespace SqMod { +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(SqDpUser, _SC("SqDiscordUser")) +SQMOD_DECL_TYPENAME(SqDpUserIdentifier, _SC("SqDiscordUser")) +// ------------------------------------------------------------------------------------------------ +void Register_Discord_User(HSQUIRRELVM vm, Table & ns) +{ + // -------------------------------------------------------------------------------------------- + ns.Bind(_SC("User"), + Class< DpUserIdentifier, NoCopy< DpUser > >(vm, SqDpUser::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqDpUser::Fn) + // Member Properties + .Prop(_SC("Valid"), &DpUser::IsValid) + .Prop(_SC("Identified"), &DpUser::IsIdentified) + .Prop(_SC("JSON"), &DpUser::BuildJSON) + .Prop(_SC("CreationTime"), &DpUser::GetCreationTime) + .Prop(_SC("Name"), &DpUser::GetName, &DpUser::SetName) + .Prop(_SC("Avatar"), &DpUser::GetAvatar, &DpUser::SetAvatar) + .Prop(_SC("Flags"), &DpUser::GetFlags, &DpUser::SetFlags) + .Prop(_SC("Discriminator"), &DpUser::GetDiscriminator, &DpUser::SetDiscriminator) + .Prop(_SC("RefCount"), &DpUser::GetRefCount, &DpUser::SetRefCount) + .Prop(_SC("AvatarUrl"), &DpUser::GetAvatarUrl) + .Prop(_SC("DefaultAvatarUrl"), &DpUser::GetDefaultAvatarUrl) + .Prop(_SC("Mention"), &DpUser::GetMention) + .Prop(_SC("IsActiveDeveloper"), &DpUser::IsActiveDeveloper) + .Prop(_SC("IsBot"), &DpUser::IsBot) + .Prop(_SC("IsSystem"), &DpUser::IsSystem) + .Prop(_SC("IsMfaEnabled"), &DpUser::IsMfaEnabled) + .Prop(_SC("IsVerified"), &DpUser::IsVerified) + .Prop(_SC("HasNitroFull"), &DpUser::HasNitroFull) + .Prop(_SC("HasNitroClassic"), &DpUser::HasNitroClassic) + .Prop(_SC("HasNitroBasic"), &DpUser::HasNitroBasic) + .Prop(_SC("IsDiscordEmployee"), &DpUser::IsDiscordEmployee) + .Prop(_SC("IsPartneredOwner"), &DpUser::IsPartneredOwner) + .Prop(_SC("HasHypesquadEvents"), &DpUser::HasHypesquadEvents) + .Prop(_SC("IsBughunter1"), &DpUser::IsBughunter1) + .Prop(_SC("IsHouseBravery"), &DpUser::IsHouseBravery) + .Prop(_SC("IsHouseBrilliance"), &DpUser::IsHouseBrilliance) + .Prop(_SC("IsHouseBalance"), &DpUser::IsHouseBalance) + .Prop(_SC("IsEarlySupporter"), &DpUser::IsEarlySupporter) + .Prop(_SC("IsTeamUser"), &DpUser::IsTeamUser) + .Prop(_SC("IsBughunter2"), &DpUser::IsBughunter2) + .Prop(_SC("IsVerifiedBot"), &DpUser::IsVerifiedBot) + .Prop(_SC("IsVerifiedBotDev"), &DpUser::IsVerifiedBotDev) + .Prop(_SC("IsCertifiedModerator"), &DpUser::IsCertifiedModerator) + .Prop(_SC("IsBotHttpInteractions"), &DpUser::IsBotHttpInteractions) + .Prop(_SC("HasAnimatedIcon"), &DpUser::HasAnimatedIcon) + // Member Methods + .Func(_SC("SetName"), &DpUser::ApplyName) + .Func(_SC("SetFlags"), &DpUser::ApplyFlags) + .Func(_SC("SetDiscriminator"), &DpUser::ApplyDiscriminator) + .Func(_SC("BuildJSON"), &DpUser::BuildJSON_) + .Func(_SC("GetMention"), &DpUser::GetMention) + .Func(_SC("FormatUsername"), &DpUser::FormatUsername) + // Member Overloads + .Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl) + .Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl_1) + .Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl_2) + .Overload(_SC("GetAvatarUrl"), &DpUser::GetAvatarUrl_3) + ); + // -------------------------------------------------------------------------------------------- + ns.Bind(_SC("UserIdentifier"), + Class< DpUserIdentifier, NoCopy< DpUserIdentifier > >(vm, SqDpUserIdentifier::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqDpUserIdentifier::Fn) + // Member Properties + .Prop(_SC("Valid"), &DpUserIdentifier::IsValid) + .Prop(_SC("Identified"), &DpUserIdentifier::IsIdentified) + .Prop(_SC("JSON"), &DpUserIdentifier::BuildJSON) + .Prop(_SC("CreationTime"), &DpUserIdentifier::GetCreationTime) + .Prop(_SC("Name"), &DpUserIdentifier::GetName, &DpUserIdentifier::SetName) + .Prop(_SC("Avatar"), &DpUserIdentifier::GetAvatar, &DpUserIdentifier::SetAvatar) + .Prop(_SC("Flags"), &DpUserIdentifier::GetFlags, &DpUserIdentifier::SetFlags) + .Prop(_SC("Discriminator"), &DpUserIdentifier::GetDiscriminator, &DpUserIdentifier::SetDiscriminator) + .Prop(_SC("RefCount"), &DpUserIdentifier::GetRefCount, &DpUserIdentifier::SetRefCount) + .Prop(_SC("AvatarUrl"), &DpUserIdentifier::GetAvatarUrl) + .Prop(_SC("DefaultAvatarUrl"), &DpUserIdentifier::GetDefaultAvatarUrl) + .Prop(_SC("Mention"), &DpUserIdentifier::GetMention) + .Prop(_SC("IsActiveDeveloper"), &DpUserIdentifier::IsActiveDeveloper) + .Prop(_SC("IsBot"), &DpUserIdentifier::IsBot) + .Prop(_SC("IsSystem"), &DpUserIdentifier::IsSystem) + .Prop(_SC("IsMfaEnabled"), &DpUserIdentifier::IsMfaEnabled) + .Prop(_SC("IsVerified"), &DpUserIdentifier::IsVerified) + .Prop(_SC("HasNitroFull"), &DpUserIdentifier::HasNitroFull) + .Prop(_SC("HasNitroClassic"), &DpUserIdentifier::HasNitroClassic) + .Prop(_SC("HasNitroBasic"), &DpUserIdentifier::HasNitroBasic) + .Prop(_SC("IsDiscordEmployee"), &DpUserIdentifier::IsDiscordEmployee) + .Prop(_SC("IsPartneredOwner"), &DpUserIdentifier::IsPartneredOwner) + .Prop(_SC("HasHypesquadEvents"), &DpUserIdentifier::HasHypesquadEvents) + .Prop(_SC("IsBughunter1"), &DpUserIdentifier::IsBughunter1) + .Prop(_SC("IsHouseBravery"), &DpUserIdentifier::IsHouseBravery) + .Prop(_SC("IsHouseBrilliance"), &DpUserIdentifier::IsHouseBrilliance) + .Prop(_SC("IsHouseBalance"), &DpUserIdentifier::IsHouseBalance) + .Prop(_SC("IsEarlySupporter"), &DpUserIdentifier::IsEarlySupporter) + .Prop(_SC("IsTeamUser"), &DpUserIdentifier::IsTeamUser) + .Prop(_SC("IsBughunter2"), &DpUserIdentifier::IsBughunter2) + .Prop(_SC("IsVerifiedBot"), &DpUserIdentifier::IsVerifiedBot) + .Prop(_SC("IsVerifiedBotDev"), &DpUserIdentifier::IsVerifiedBotDev) + .Prop(_SC("IsCertifiedModerator"), &DpUserIdentifier::IsCertifiedModerator) + .Prop(_SC("IsBotHttpInteractions"), &DpUserIdentifier::IsBotHttpInteractions) + .Prop(_SC("HasAnimatedIcon"), &DpUserIdentifier::HasAnimatedIcon) + .Prop(_SC("HasAnimatedBanner"), &DpUserIdentifier::HasAnimatedBanner) + .Prop(_SC("Banner"), &DpUserIdentifier::GetBanner, &DpUserIdentifier::SetBanner) + .Prop(_SC("Locale"), &DpUserIdentifier::GetLocale, &DpUserIdentifier::SetLocale) + .Prop(_SC("Email"), &DpUserIdentifier::GetEmail, &DpUserIdentifier::SetEmail) + .Prop(_SC("AccentColor"), &DpUserIdentifier::GetAccentColor, &DpUserIdentifier::SetAccentColor) + .Prop(_SC("Verified"), &DpUserIdentifier::GetVerified, &DpUserIdentifier::SetVerified) + .Prop(_SC("BannerUrl"), &DpUserIdentifier::GetBannerUrl) + // Member Methods + .Func(_SC("SetName"), &DpUserIdentifier::ApplyName) + .Func(_SC("SetFlags"), &DpUserIdentifier::ApplyFlags) + .Func(_SC("SetDiscriminator"), &DpUserIdentifier::ApplyDiscriminator) + .Func(_SC("BuildJSON"), &DpUserIdentifier::BuildJSON_) + .Func(_SC("GetMention"), &DpUserIdentifier::GetMention) + .Func(_SC("FormatUsername"), &DpUserIdentifier::FormatUsername) + .Func(_SC("SetLocale"), &DpUserIdentifier::ApplyLocale) + .Func(_SC("SetEmail"), &DpUserIdentifier::ApplyEmail) + .Func(_SC("SetAccentColor"), &DpUserIdentifier::ApplyAccentColor) + // Member Overloads + .Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl) + .Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl_1) + .Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl_2) + .Overload(_SC("GetAvatarUrl"), &DpUserIdentifier::GetAvatarUrl_3) + .Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl) + .Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl_1) + .Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl_2) + .Overload(_SC("GetBannerUrl"), &DpUserIdentifier::GetBannerUrl_3) + ); +} } // Namespace:: SqMod diff --git a/module/Library/Discord/User.hpp b/module/Library/Discord/User.hpp index ab7ce4d7..53c476d1 100644 --- a/module/Library/Discord/User.hpp +++ b/module/Library/Discord/User.hpp @@ -9,5 +9,541 @@ // ------------------------------------------------------------------------------------------------ namespace SqMod { +/* ------------------------------------------------------------------------------------------------ + * Represents a user on discord. May or may not be a member of a DpGuild. +*/ +struct DpUser +{ + using Ptr = std::unique_ptr< dpp::user >; + /* -------------------------------------------------------------------------------------------- + * Referenced voice state instance. + */ + Ptr mPtr{nullptr}; + /* -------------------------------------------------------------------------------------------- + * Whether the referenced pointer is owned. + */ + bool mOwned{false}; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + DpUser() noexcept = default; + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + explicit DpUser(Ptr::pointer ptr, bool owned = false) noexcept + : mPtr(ptr), mOwned(owned) + { + } + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + explicit DpUser(const Ptr::element_type & o) noexcept + : DpUser(new Ptr::element_type(o), true) + { + } + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit DpUser(Ptr::element_type && o) noexcept + : DpUser(new Ptr::element_type(std::forward< Ptr::element_type >(o)), true) + { + } + /* -------------------------------------------------------------------------------------------- + * Copy constructor (disabled). + */ + DpUser(const DpUser & o) = delete; + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + DpUser(DpUser && o) noexcept = default; + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~DpUser() noexcept { Cleanup(); } + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator (disabled). + */ + DpUser & operator=(const DpUser & o) = delete; + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + DpUser & operator=(DpUser && o) noexcept + { + if (this != &o) + { + Cleanup(); + // Transfer members values + mPtr = std::move(o.mPtr); + mOwned = o.mOwned; + } + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Release any referenced resources and default to an empty/invalid state. + */ + void Cleanup() + { + // Do we own this to try delete it? + if (!mOwned && mPtr) + { + // Not our job, simply forget about it + [[maybe_unused]] auto p = mPtr.release(); + } + else + mPtr.reset(); // We own this so delete the instance + } + /* -------------------------------------------------------------------------------------------- + * Validate the managed handle. + */ + void Validate() const + { + if (!mPtr) + STHROWF("Invalid discord user handle"); + } + /* -------------------------------------------------------------------------------------------- + * Validate the managed handle and retrieve a const reference to it. + */ + SQMOD_NODISCARD Ptr::element_type & Valid() const + { + Validate(); + return *mPtr; + } + /* -------------------------------------------------------------------------------------------- + * Check whether a valid instance is managed. + */ + SQMOD_NODISCARD bool IsValid() const { return static_cast(mPtr); } + /* -------------------------------------------------------------------------------------------- + * Check whether this represents an identified user. + */ + SQMOD_NODISCARD bool IsIdentified() const { return false; } + /* -------------------------------------------------------------------------------------------- + * Get the creation time of this object according to Discord. + */ + SQMOD_NODISCARD SQFloat GetCreationTime() const { return Valid().get_creation_time(); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the name of the user. + */ + SQMOD_NODISCARD const std::string & GetName() const { return Valid().username; } + /* -------------------------------------------------------------------------------------------- + * Modify the name of the user. + */ + void SetName(StackStrF & name) const { Valid().username = name.ToStr(); } + /* -------------------------------------------------------------------------------------------- + * Modify the name of the user. + */ + DpUser & ApplyName(StackStrF & name) + { + SetName(name); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the avatar hash of the user. + */ + SQMOD_NODISCARD const dpp::utility::iconhash & GetAvatar() const { return Valid().avatar; } + /* -------------------------------------------------------------------------------------------- + * Modify the avatar hash of the user. + */ + void SetAvatar(dpp::utility::iconhash & avatar) const { Valid().avatar = avatar; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the flags for the user from SqDiscordUserFlags. + */ + SQMOD_NODISCARD SQInteger GetFlags() const { return Valid().flags; } + /* -------------------------------------------------------------------------------------------- + * Modify the flags for the user from SqDiscordUserFlags. + */ + void SetFlags(SQInteger flags) const { Valid().flags = static_cast< uint32_t >(flags); } + /* -------------------------------------------------------------------------------------------- + * Modify the flags for the user from SqDiscordUserFlags. + */ + DpUser & ApplyFlags(SQInteger flags) + { + SetFlags(flags); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the discriminator (aka tag), 4 digits usually displayed with leading zeroes for the user. + * To print the discriminator with leading zeroes, use FormatUsername() + */ + SQMOD_NODISCARD SQInteger GetDiscriminator() const { return Valid().discriminator; } + /* -------------------------------------------------------------------------------------------- + * Modify the discriminator for the user. + */ + void SetDiscriminator(SQInteger discriminator) const { Valid().discriminator = static_cast< uint16_t >(discriminator); } + /* -------------------------------------------------------------------------------------------- + * Modify the discriminator for the user. + */ + DpUser & ApplyDiscriminator(SQInteger discriminator) + { + SetDiscriminator(discriminator); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the reference count of how many guilds this user is in. + */ + SQMOD_NODISCARD SQInteger GetRefCount() const { return Valid().refcount; } + /* -------------------------------------------------------------------------------------------- + * Modify the reference count of how many guilds this user is in. + */ + void SetRefCount(SQInteger refcount) const { Valid().refcount = static_cast< uint8_t >(refcount); } + /* -------------------------------------------------------------------------------------------- + * Build JSON string from this user. + */ + SQMOD_NODISCARD std::string BuildJSON() const { return Valid().build_json(); } + SQMOD_NODISCARD std::string BuildJSON_(bool with_id) const { return Valid().build_json(with_id); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the avatar url of the user. + * If the user doesn't have an avatar, the default user avatar url is returned which is always in `png` format! + * Size of the avatar is in pixels. It can be any power of two between 16 and 4096. + * Check SqDiscordImageType enum for available image formats. + */ + SQMOD_NODISCARD std::string GetAvatarUrl() const { return Valid().get_avatar_url(); } + SQMOD_NODISCARD std::string GetAvatarUrl_1(uint16_t size) const { return Valid().get_avatar_url(size); } + SQMOD_NODISCARD std::string GetAvatarUrl_2(uint16_t size, SQInteger format) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format)); } + SQMOD_NODISCARD std::string GetAvatarUrl_3(uint16_t size, SQInteger format, bool prefer_animated) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format), prefer_animated); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the default avatar url of the user. This is calculated by the discriminator. + */ + SQMOD_NODISCARD std::string GetDefaultAvatarUrl() const { return Valid().get_default_avatar_url(); } + /* -------------------------------------------------------------------------------------------- + * Retrieve a ping/mention for the user. + */ + SQMOD_NODISCARD std::string GetMention() const { return Valid().get_mention(); } + /* -------------------------------------------------------------------------------------------- + * Format a username into user\#discriminator. For example Brain#0001 + */ + SQMOD_NODISCARD std::string FormatUsername() const { return Valid().format_username(); } + /* -------------------------------------------------------------------------------------------- + * Helper methods for flags. + */ + SQMOD_NODISCARD bool IsActiveDeveloper() const { return Valid().is_active_developer(); } + SQMOD_NODISCARD bool IsBot() const { return Valid().is_bot(); } + SQMOD_NODISCARD bool IsSystem() const { return Valid().is_system(); } + SQMOD_NODISCARD bool IsMfaEnabled() const { return Valid().is_mfa_enabled(); } + SQMOD_NODISCARD bool IsVerified() const { return Valid().is_verified(); } + SQMOD_NODISCARD bool HasNitroFull() const { return Valid().has_nitro_full(); } + SQMOD_NODISCARD bool HasNitroClassic() const { return Valid().has_nitro_classic(); } + SQMOD_NODISCARD bool HasNitroBasic() const { return Valid().has_nitro_basic(); } + SQMOD_NODISCARD bool IsDiscordEmployee() const { return Valid().is_discord_employee(); } + SQMOD_NODISCARD bool IsPartneredOwner() const { return Valid().is_partnered_owner(); } + SQMOD_NODISCARD bool HasHypesquadEvents() const { return Valid().has_hypesquad_events(); } + SQMOD_NODISCARD bool IsBughunter1() const { return Valid().is_bughunter_1(); } + SQMOD_NODISCARD bool IsHouseBravery() const { return Valid().is_house_bravery(); } + SQMOD_NODISCARD bool IsHouseBrilliance() const { return Valid().is_house_brilliance(); } + SQMOD_NODISCARD bool IsHouseBalance() const { return Valid().is_house_balance(); } + SQMOD_NODISCARD bool IsEarlySupporter() const { return Valid().is_early_supporter(); } + SQMOD_NODISCARD bool IsTeamUser() const { return Valid().is_team_user(); } + SQMOD_NODISCARD bool IsBughunter2() const { return Valid().is_bughunter_2(); } + SQMOD_NODISCARD bool IsVerifiedBot() const { return Valid().is_verified_bot(); } + SQMOD_NODISCARD bool IsVerifiedBotDev() const { return Valid().is_verified_bot_dev(); } + SQMOD_NODISCARD bool IsCertifiedModerator() const { return Valid().is_certified_moderator(); } + SQMOD_NODISCARD bool IsBotHttpInteractions() const { return Valid().is_bot_http_interactions(); } + SQMOD_NODISCARD bool HasAnimatedIcon() const { return Valid().has_animated_icon(); } +}; + +/* ------------------------------------------------------------------------------------------------ + * A user with additional fields only available via the oauth2 identify scope. + * These are not included in DpUser as additional scopes are needed to fetch them which bots do not normally have. +*/ +struct DpUserIdentifier +{ + using Ptr = std::unique_ptr< dpp::user_identified >; + /* -------------------------------------------------------------------------------------------- + * Referenced voice state instance. + */ + Ptr mPtr{nullptr}; + /* -------------------------------------------------------------------------------------------- + * Whether the referenced pointer is owned. + */ + bool mOwned{false}; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + DpUserIdentifier() noexcept = default; + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + explicit DpUserIdentifier(Ptr::pointer ptr, bool owned = false) noexcept + : mPtr(ptr), mOwned(owned) + { + } + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + explicit DpUserIdentifier(const Ptr::element_type & o) noexcept + : DpUserIdentifier(new Ptr::element_type(o), true) + { + } + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit DpUserIdentifier(Ptr::element_type && o) noexcept + : DpUserIdentifier(new Ptr::element_type(std::forward< Ptr::element_type >(o)), true) + { + } + /* -------------------------------------------------------------------------------------------- + * Copy constructor (disabled). + */ + DpUserIdentifier(const DpUserIdentifier & o) = delete; + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + DpUserIdentifier(DpUserIdentifier && o) noexcept = default; + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~DpUserIdentifier() noexcept { Cleanup(); } + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator (disabled). + */ + DpUserIdentifier & operator=(const DpUserIdentifier & o) = delete; + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + DpUserIdentifier & operator=(DpUserIdentifier && o) noexcept + { + if (this != &o) + { + Cleanup(); + // Transfer members values + mPtr = std::move(o.mPtr); + mOwned = o.mOwned; + } + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Release any referenced resources and default to an empty/invalid state. + */ + void Cleanup() + { + // Do we own this to try delete it? + if (!mOwned && mPtr) + { + // Not our job, simply forget about it + [[maybe_unused]] auto p = mPtr.release(); + } + else + mPtr.reset(); // We own this so delete the instance + } + /* -------------------------------------------------------------------------------------------- + * Validate the managed handle. + */ + void Validate() const + { + if (!mPtr) + STHROWF("Invalid discord user handle"); + } + /* -------------------------------------------------------------------------------------------- + * Validate the managed handle and retrieve a const reference to it. + */ + SQMOD_NODISCARD Ptr::element_type & Valid() const + { + Validate(); + return *mPtr; + } + /* -------------------------------------------------------------------------------------------- + * Check whether a valid instance is managed. + */ + SQMOD_NODISCARD bool IsValid() const { return static_cast(mPtr); } + /* -------------------------------------------------------------------------------------------- + * Check whether this represents an identified user. + */ + SQMOD_NODISCARD bool IsIdentified() const { return false; } + /* -------------------------------------------------------------------------------------------- + * Get the creation time of this object according to Discord. + */ + SQMOD_NODISCARD SQFloat GetCreationTime() const { return Valid().get_creation_time(); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the name of the user. + */ + SQMOD_NODISCARD const std::string & GetName() const { return Valid().username; } + /* -------------------------------------------------------------------------------------------- + * Modify the name of the user. + */ + void SetName(StackStrF & name) const { Valid().username = name.ToStr(); } + /* -------------------------------------------------------------------------------------------- + * Modify the name of the user. + */ + DpUserIdentifier & ApplyName(StackStrF & name) + { + SetName(name); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the avatar hash of the user. + */ + SQMOD_NODISCARD const dpp::utility::iconhash & GetAvatar() const { return Valid().avatar; } + /* -------------------------------------------------------------------------------------------- + * Modify the avatar hash of the user. + */ + void SetAvatar(dpp::utility::iconhash & avatar) const { Valid().avatar = avatar; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the flags for the user from SqDiscordUserFlags. + */ + SQMOD_NODISCARD SQInteger GetFlags() const { return Valid().flags; } + /* -------------------------------------------------------------------------------------------- + * Modify the flags for the user from SqDiscordUserFlags. + */ + void SetFlags(SQInteger flags) const { Valid().flags = static_cast< uint32_t >(flags); } + /* -------------------------------------------------------------------------------------------- + * Modify the flags for the user from SqDiscordUserFlags. + */ + DpUserIdentifier & ApplyFlags(SQInteger flags) + { + SetFlags(flags); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the discriminator (aka tag), 4 digits usually displayed with leading zeroes for the user. + * To print the discriminator with leading zeroes, use FormatUsername() + */ + SQMOD_NODISCARD SQInteger GetDiscriminator() const { return Valid().discriminator; } + /* -------------------------------------------------------------------------------------------- + * Modify the discriminator for the user. + */ + void SetDiscriminator(SQInteger discriminator) const { Valid().discriminator = static_cast< uint16_t >(discriminator); } + /* -------------------------------------------------------------------------------------------- + * Modify the discriminator for the user. + */ + DpUserIdentifier & ApplyDiscriminator(SQInteger discriminator) + { + SetDiscriminator(discriminator); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the reference count of how many guilds this user is in. + */ + SQMOD_NODISCARD SQInteger GetRefCount() const { return Valid().refcount; } + /* -------------------------------------------------------------------------------------------- + * Modify the reference count of how many guilds this user is in. + */ + void SetRefCount(SQInteger refcount) const { Valid().refcount = static_cast< uint8_t >(refcount); } + /* -------------------------------------------------------------------------------------------- + * Build JSON string from this user. + */ + SQMOD_NODISCARD std::string BuildJSON() const { return Valid().build_json(); } + SQMOD_NODISCARD std::string BuildJSON_(bool with_id) const { return Valid().build_json(with_id); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the avatar url of the user. + * If the user doesn't have an avatar, the default user avatar url is returned which is always in `png` format! + * Size of the avatar is in pixels. It can be any power of two between 16 and 4096. + * Check SqDiscordImageType enum for available image formats. + */ + SQMOD_NODISCARD std::string GetAvatarUrl() const { return Valid().get_avatar_url(); } + SQMOD_NODISCARD std::string GetAvatarUrl_1(uint16_t size) const { return Valid().get_avatar_url(size); } + SQMOD_NODISCARD std::string GetAvatarUrl_2(uint16_t size, SQInteger format) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format)); } + SQMOD_NODISCARD std::string GetAvatarUrl_3(uint16_t size, SQInteger format, bool prefer_animated) const { return Valid().get_avatar_url(size, static_cast< dpp::image_type >(format), prefer_animated); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the default avatar url of the user. This is calculated by the discriminator. + */ + SQMOD_NODISCARD std::string GetDefaultAvatarUrl() const { return Valid().get_default_avatar_url(); } + /* -------------------------------------------------------------------------------------------- + * Retrieve a ping/mention for the user. + */ + SQMOD_NODISCARD std::string GetMention() const { return Valid().get_mention(); } + /* -------------------------------------------------------------------------------------------- + * Format a username into user\#discriminator. For example Brain#0001 + */ + SQMOD_NODISCARD std::string FormatUsername() const { return Valid().format_username(); } + /* -------------------------------------------------------------------------------------------- + * Helper methods for flags. + */ + SQMOD_NODISCARD bool IsActiveDeveloper() const { return Valid().is_active_developer(); } + SQMOD_NODISCARD bool IsBot() const { return Valid().is_bot(); } + SQMOD_NODISCARD bool IsSystem() const { return Valid().is_system(); } + SQMOD_NODISCARD bool IsMfaEnabled() const { return Valid().is_mfa_enabled(); } + SQMOD_NODISCARD bool IsVerified() const { return Valid().is_verified(); } + SQMOD_NODISCARD bool HasNitroFull() const { return Valid().has_nitro_full(); } + SQMOD_NODISCARD bool HasNitroClassic() const { return Valid().has_nitro_classic(); } + SQMOD_NODISCARD bool HasNitroBasic() const { return Valid().has_nitro_basic(); } + SQMOD_NODISCARD bool IsDiscordEmployee() const { return Valid().is_discord_employee(); } + SQMOD_NODISCARD bool IsPartneredOwner() const { return Valid().is_partnered_owner(); } + SQMOD_NODISCARD bool HasHypesquadEvents() const { return Valid().has_hypesquad_events(); } + SQMOD_NODISCARD bool IsBughunter1() const { return Valid().is_bughunter_1(); } + SQMOD_NODISCARD bool IsHouseBravery() const { return Valid().is_house_bravery(); } + SQMOD_NODISCARD bool IsHouseBrilliance() const { return Valid().is_house_brilliance(); } + SQMOD_NODISCARD bool IsHouseBalance() const { return Valid().is_house_balance(); } + SQMOD_NODISCARD bool IsEarlySupporter() const { return Valid().is_early_supporter(); } + SQMOD_NODISCARD bool IsTeamUser() const { return Valid().is_team_user(); } + SQMOD_NODISCARD bool IsBughunter2() const { return Valid().is_bughunter_2(); } + SQMOD_NODISCARD bool IsVerifiedBot() const { return Valid().is_verified_bot(); } + SQMOD_NODISCARD bool IsVerifiedBotDev() const { return Valid().is_verified_bot_dev(); } + SQMOD_NODISCARD bool IsCertifiedModerator() const { return Valid().is_certified_moderator(); } + SQMOD_NODISCARD bool IsBotHttpInteractions() const { return Valid().is_bot_http_interactions(); } + SQMOD_NODISCARD bool HasAnimatedIcon() const { return Valid().has_animated_icon(); } + SQMOD_NODISCARD bool HasAnimatedBanner() const { return Valid().has_animated_banner(); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the locale of the user. + */ + SQMOD_NODISCARD const std::string & GetLocale() const { return Valid().locale; } + /* -------------------------------------------------------------------------------------------- + * Modify the locale of the user. + */ + void SetLocale(StackStrF & locale) const { Valid().locale = locale.ToStr(); } + /* -------------------------------------------------------------------------------------------- + * Modify the locale of the user. + */ + DpUserIdentifier & ApplyLocale(StackStrF & locale) + { + SetLocale(locale); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the locale of the user. + */ + SQMOD_NODISCARD const std::string & GetEmail() const { return Valid().email; } + /* -------------------------------------------------------------------------------------------- + * Modify the email of the user. + */ + void SetEmail(StackStrF & email) const { Valid().email = email.ToStr(); } + /* -------------------------------------------------------------------------------------------- + * Modify the email of the user. + */ + DpUserIdentifier & ApplyEmail(StackStrF & email) + { + SetEmail(email); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve the banner hash of the user. + */ + SQMOD_NODISCARD const dpp::utility::iconhash & GetBanner() const { return Valid().banner; } + /* -------------------------------------------------------------------------------------------- + * Modify the banner hash of the user. + */ + void SetBanner(dpp::utility::iconhash & banner) const { Valid().banner = banner; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the banner color encoded as an integer representation of hexadecimal color code for the user. + */ + SQMOD_NODISCARD SQInteger GetAccentColor() const { return Valid().accent_color; } + /* -------------------------------------------------------------------------------------------- + * Modify the banner color encoded as an integer representation of hexadecimal color code for the user. + */ + void SetAccentColor(SQInteger color) const { Valid().accent_color = static_cast< uint32_t >(color); } + /* -------------------------------------------------------------------------------------------- + * Modify the banner color encoded as an integer representation of hexadecimal color code for the user. + */ + DpUserIdentifier & ApplyAccentColor(SQInteger color) + { + SetAccentColor(color); + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Retrieve whether the email on this account has been verified. + */ + SQMOD_NODISCARD bool GetVerified() const { return Valid().verified; } + /* -------------------------------------------------------------------------------------------- + * Modify whether the email on this account has been verified. + */ + void SetVerified(bool verified) const { Valid().verified = verified; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the banner url of the user, if they have one, otherwise returns an empty string. + * Size of the avatar is in pixels. It can be any power of two between 16 and 4096. + * Check SqDiscordImageType enum for available image formats. + */ + SQMOD_NODISCARD std::string GetBannerUrl() const { return Valid().get_banner_url(); } + SQMOD_NODISCARD std::string GetBannerUrl_1(uint16_t size) const { return Valid().get_banner_url(size); } + SQMOD_NODISCARD std::string GetBannerUrl_2(uint16_t size, SQInteger format) const { return Valid().get_banner_url(size, static_cast< dpp::image_type >(format)); } + SQMOD_NODISCARD std::string GetBannerUrl_3(uint16_t size, SQInteger format, bool prefer_animated) const { return Valid().get_banner_url(size, static_cast< dpp::image_type >(format), prefer_animated); } +}; } // Namespace:: SqMod diff --git a/module/Library/Discord/Utilities.hpp b/module/Library/Discord/Utilities.hpp index dc96af87..bf5b201b 100644 --- a/module/Library/Discord/Utilities.hpp +++ b/module/Library/Discord/Utilities.hpp @@ -445,6 +445,9 @@ template < class T, class W > struct DpVectorProxy } }; +/* ------------------------------------------------------------------------------------------------ + * Register a wrapper vector for the specified types. +*/ template < class T, class W, class U > inline void Register_Discord_VectorProxy(HSQUIRRELVM vm, Table & ns, const SQChar * name) { using Container = DpVectorProxy< T, W >; @@ -476,4 +479,54 @@ template < class T, class W, class U > inline void Register_Discord_VectorProxy( ); } +/* ------------------------------------------------------------------------------------------------ + * Wrapper around a std::unordered_map of DPP values. +*/ +template < class K, class V, class W > struct DpUnorderedMapProxy +{ +{ + using Native = std::unordered_map< K, V >; + using Binder = std::pair< LightObj, W * >; + using Script = std::unordered_map< K, Binder >; + using Ptr = std::unique_ptr< Native >; + /* -------------------------------------------------------------------------------------------- + * Referenced map instance. + */ + Ptr mPtr{nullptr}; + /* -------------------------------------------------------------------------------------------- + * Cached script objects map. + */ + Script mMap{}; + /* -------------------------------------------------------------------------------------------- + * Whether the referenced pointer is owned. + */ + bool mOwned{false}; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + DpUnorderedMapProxy() noexcept = default; +} + +/* ------------------------------------------------------------------------------------------------ + * Register a wrapper unordered map for the specified types. +*/ +template < class K, class V, class W, class U > inline void Register_Discord_UnorderedMapProxy(HSQUIRRELVM vm, Table & ns, const SQChar * name) +{ + using Container = DpUnorderedMapProxy< K, V, W >; + // -------------------------------------------------------------------------------------------- + ns.Bind(name, + Class< Container, NoConstructor< Container > >(vm, U::Str) + // Meta-methods + .SquirrelFunc(_SC("_typename"), &U::Fn) + // Properties + //.Prop(_SC("Null"), &Container::IsNull) + //.Prop(_SC("Empty"), &Container::Empty) + //.Prop(_SC("Size"), &Container::Size) + //.Prop(_SC("Capacity"), &Container::Capacity, &Container::Reserve) + // Member Methods + //.Func(_SC("Get"), &Container::Get) + //.Func(_SC("Set"), &Container::Set) + ); +} + } // Namespace:: SqMod